如何获取网站根目录链接,福州市做公司网站哪家好,南沙营销网站建设,wordpress 主题 数据库文章目录 前言一、多态二、rust实现多态trait的静态方式还有一种方式可以通过动态分发#xff0c;还以上面那段代码#xff0c;比如dyn关键字 泛型方式枚举方式优点#xff1a;缺点#xff1a; 总结 前言
学习rust当中遇到了这个问题#xff0c;记录一下#xff0c;不对… 文章目录 前言一、多态二、rust实现多态trait的静态方式还有一种方式可以通过动态分发还以上面那段代码比如dyn关键字 泛型方式枚举方式优点缺点 总结 前言
学习rust当中遇到了这个问题记录一下不对地方望指正
一、多态
多态是面向对象程序设计中的一个重要概念指同一个行为或操作在不同实例上具有不同的行为或结果。简单来说多态就是指同一种类型的对象在不同的上下文中有不同的行为。多态性使得程序可以更加灵活、可扩展和易于维护。在实现多态性时通常会使用继承、接口、抽象类等技术
二、rust实现多态
trait的静态方式 trait Animal {fn make_sound(self);
}
struct Cat {}impl Animal for Cat {fn make_sound(self) {println!(Meow);}
}
struct Dog {}impl Animal for Dog {fn make_sound(self) {println!(Woof);}
}fn main() {let cat: Cat Cat {};let dog: Dog Dog {};test(cat);test(dog)
}
//接受Animal Trait类型的
fn test(animal : impl Animal){animal.make_sound()
}定义了方法传入参数是trait。这一种在实例化的时候是具体的类型在传参的时候编译器能推断出来具体是cat还是dog能调用具体方法
还有一种方式可以通过动态分发还以上面那段代码比如
trait Animal {fn make_sound(self);
}struct Cat {}impl Animal for Cat {fn make_sound(self) {println!(Meow);}
}struct Dog {}impl Animal for Dog {fn make_sound(self) {println!(Woof);}
}fn main() {let cat: Boxdyn Animal Box::new(Cat {});let dog: Boxdyn Animal Box::new(Dog {});test(cat);test(dog)
}fn test(animal: Boxdyn Animal) {animal.make_sound()
}这种方式相对于上面更加灵活因为实例化参数变量类型是trait类型。现在说说关键点
dyn关键字
dyn关键字是在Rust中用于创建和使用动态分发的trait对象的关键字。trait对象允许我们以统一的方式处理不同类型的对象并使用相同的方法调用语法。使用动态分发编译器无需在编译时知道具体的类型而是在运行时根据对象的实际类型来确定要调用的方法。要创建一个trait对象需要在trait名称前加上dyn关键字。例如对于名为TraitName的trait我们可以使用dyn TraitName来创建一个trait对象。
trait TraitName {// trait定义
}fn main() {let trait_obj: Boxdyn TraitName Box::new(ConcreteType);// 在这里使用trait对象
}在上面的代码中trait_obj是一个Box指向动态分发的trait对象的指针。它可以存储实现了TraitName trait的任何具体类型的对象。通过dyn关键字我们可以在运行时根据实际类型来调用trait定义的方法。 这里要注意trait对象通过指针或引用来操作因此通常结合使用Box、或mut来创建和使用trait对象。为了在运行时确定对象的大小我们需要将它们放置在一个固定大小的容器中。这就是为什么要使用Box来包装trait对象的原因。Box类型表示一个动态分发的trait对象。它在堆上分配一块内存该内存用于存储对象的数据并提供一个指向虚函数表vtable的指针该表用于在运行时查找和调用正确的方法。 这种方式相对于静态方式会更加灵活但会有运行时性能损失看情况决定使用哪一种
泛型方式
use std::fmt::{Display, Formatter};struct Cat {}struct Dog {}impl Display for Cat{fn fmt(self, f: mut Formatter_) - std::fmt::Result {write!(f,Cat)}
}impl Display for Dog{fn fmt(self, f: mut Formatter_) - std::fmt::Result {write!(f,Dog)}
}fn make_soundT: Display(animal: T) {println!({}, animal);
}fn main() {make_sound(Cat{});make_sound(Dog{});
}通过在函数签名中使用泛型类型参数函数可以接受不同类型的参数并在编译时生成对应的具体化代码。这种方式不依赖于trait而是基于类型推断和编译时的静态分发
枚举方式
还有一种方式是使用枚举方式例如
enum Shape {Circle(f64),Square(f64),Rectangle(f64, f64),
}impl Shape {fn area(self) - f64 {match *self {Shape::Circle(radius) std::f64::consts::PI * radius * radius,Shape::Square(side_length) side_length * side_length,Shape::Rectangle(length, width) length * width,}}
}fn main() {let circle Shape::Circle(5.0);let square Shape::Square(4.0);let rectangle Shape::Rectangle(3.0, 6.0);test(circle);test(square);test(rectangle);
}fn test(shape: Shape) {println!(shape area: {}, shape.area());
}
枚举在实现多态性方面有一些优点和缺点。以下是其中的一些
优点
简洁性枚举提供了一种紧凑的方式来定义和组织具有不同变体的数据类型。它能够在一个地方集中描述和管理多种可能的状态或情况。 静态类型检查由于枚举的变体是预先定义的编译器可以在编译时验证变体的正确性。这可以帮助捕捉到潜在的错误并提供类型安全性。 模式匹配枚举与模式匹配相结合可以使代码更具表达力和可读性。模式匹配可以根据具体的变体类型执行相应的逻辑同时处理所有可能的情况避免遗漏。
缺点
限制的扩展性当需要添加新的变体时枚举需要进行修改。这可能涉及到修改已有的代码以适应新的变体。这对于外部库或包的枚举类型来说尤其困难因为无法直接修改其定义。 冗余的结构枚举的每个变体都可以存储不同的数据结构这可能会导致某些变体拥有与其他变体不相关的冗余数据。这可能会浪费内存空间尤其是当只使用其中的一部分变体时。 灵活性的限制枚举要求提前定义所有可能的变体。如果需要在运行时动态添加新的变体或者处理不确定的类型集合那么枚举可能不适合。
总结
以上就是今天要说的内容不对的地方望指正