zoukankan      html  css  js  c++  java
  • Rust 多态

    Rust 多态

    分发

    多态的上下文中的方法解析过程被称为分发,调用该方法称为分发化,在支持多态的主流语言中,分发可以通过以下任意一种方式进行。

    静态分发

    当在编译期决定要调用的方法时,它被称为静态分发或早期绑定。

    Rust中的泛型属于静态分发,因为即使泛型函数可以接收多种类型参数,但是在编译时会生成特定类型的专用副本。

    动态分发

    直到运行时才能确定调用的方法,被称为动态分发。这是因为具体类型被隐藏,只能通过接口实例调用。

    在动态分发过程中,可以通过对vtable(虚表)接口的实现列表进行查找,并调用该方法来动态确定相关方法。vtable是一个在固定偏移处为每个对象的方法保留一个函数指针的结构体。

    特征对象(trait object)

    特征对象是Rust执行动态分发的方式,它被实现为胖指针,并且是不定长类型,这意味着它们只能在引用符号(&)后面使用。特征对象胖指针具有指向与对象关联的实际数据的第一指针和指向vtable的第二指针。在运行时,我们没有实际类型的具体信息,只能通过trait的信息在vtable中找到适当的方法并调用。

    trait object实现多态:

    use std::fmt::Debug;
    #[derive(Debug)]
    struct Square(f32);
    #[derive(Debug)]
    struct Rectangle(f32,f32);
    trait Area:Debug {
        fn get_area(&self)->f32;
    }
    impl Area for Square {
        fn get_area(&self)->f32 {
            self.0*self.0
        }
    }
    impl Area for Rectangle {
        fn get_area(&self)->f32 {
            self.0*self.1
        }
    }
    fn main() {
        let s:&dyn Area=&Square(3f32);
        println!("{:?}",s.get_area());
        let rec:&dyn Area=&Rectangle(4f32,2f32);
        println!("{:?}",rec.get_area());
    }
    

    特征对象的一个用例是在一个集合中存储多种不同类型但具有共同trait的实例:

    use std::fmt::Debug;
    #[derive(Debug)]
    struct Square(f32);
    #[derive(Debug)]
    struct Rectangle(f32,f32);
    trait Area:Debug {
        fn get_area(&self)->f32;
    }
    impl Area for Square {
        fn get_area(&self)->f32 {
            self.0*self.0
        }
    }
    impl Area for Rectangle {
        fn get_area(&self)->f32 {
            self.0*self.1
        }
    }
    fn main() {
        let shapes:Vec<&dyn Area>=vec![&Square(3f32),&Rectangle(4f32,2f32)];
        for e in shapes{
            println!("{:?}",e.get_area());
        }
    }
    

    注意:上述实例将Square和Rectangle的构造为特征对象,由于我们不知道实际类型的大小,所以dyn Trait是一个不定长类型,只能作为引用使用。或者将其置于特征其他智能指针之后:

     	let s:Box<dyn Area>=Box::new(Square(3f32));
       	println!("{:?}",s.get_area());
        let rec:Box<dyn Area>=Box::new(Rectangle(4f32,2f32));
        println!("{:?}",rec.get_area());
        let shapes:Vec<Box<dyn Area>>=vec![Box::new(Square(3f32)),Box::new(Rectangle(4f32,2f32))];
        for e in shapes{
            println!("{:?}",e.get_area());
        }
    

    还可以将dyn Trait作为函数参数,以接收不同实际类型的实例参数:

    fn get_area(item:&dyn Area)->f32{
        item.get_area()
    }
    fn main() {
       let shapes:Vec<&dyn Area>=vec![&Square(3f32),&Rectangle(4f32,2f32)];
        for e in shapes{
            println!("{:?}",get_area(e));
        }
    }
    
  • 相关阅读:
    使用WebAPI流式传输大文件(在IIS上大于2GB)
    网页扫描仪图像上传
    网页高拍仪图像上传
    C++
    Tomcat Connector三种执行模式(BIO, NIO, APR)的比較和优化
    编程精粹--编写高质量C语言代码(1):假想编译程序
    一个软件项目的总纲性的測试计划叫什么?
    Java字符串的格式化与输出
    Servlet入门(第一个Servlet的Web程序)
    求职小技巧,赢得大机会
  • 原文地址:https://www.cnblogs.com/yanshaoshuai/p/14426482.html
Copyright © 2011-2022 走看看