generics-traits/trait-object #220
Replies: 27 comments 22 replies
-
fn hatch_a_bird(num: u8) -> Box<dyn Bird>{
match num {
1 => Box::new(Swan),
_ => Box::new(Duck),
}
} |
Beta Was this translation helpful? Give feedback.
-
let birds:[Box<dyn Bird>; 2] = [Box::new(Duck), Box::new(Swan)]; |
Beta Was this translation helpful? Give feedback.
-
// 通过泛型实现以下函数
fn static_dispatch<T>(param: T)
where T:Foo
{
println!("{}", param.method());
}
// 通过特征对象实现以下函数
fn dynamic_dispatch(param:&dyn Foo){
println!("{}", param.method());
} |
Beta Was this translation helpful? Give feedback.
-
第四题也可以通过 impl 语法实现,不过不知道是不是合乎规矩的 fn static_dispatch(foo: impl Foo) {
foo.method();
} |
Beta Was this translation helpful? Give feedback.
-
done,本节主要讲了特征对象的相关知识,其中使用到了dyn关键字,这个dyn关键字我觉得和rust最初的设计理念并不相符,因为rust本身是想要在编译阶段就确定所有参数的类型的,这样程序的运行时性能才会最高,dyn动态分发就破坏了这一理念,拙见,轻喷 |
Beta Was this translation helpful? Give feedback.
-
done!这里的第六题有一个新的思路,使用 泛型特征(Generic Traits) ,代码如下: trait MyTrait<T> {
fn f(&self) -> T;
}
impl MyTrait<u32> for u32 {
fn f(&self) -> u32 { 42 }
}
impl MyTrait<String> for String {
fn f(&self) -> String { self.clone() }
}
fn my_function<T: MyTrait<T>> (x: Box<dyn MyTrait<T>>) -> T { // could be discarded
x.f()
}
fn my_function_2<T: MyTrait<T>> (x: Box<T>) -> T { // could be discarded
x.f()
}
fn main() {
my_function(
Box::new(13_u32)
);
my_function(
Box::new( String::from("abc") )
);
my_function_2(
Box::new(13_u32)
);
my_function_2(
Box::new( String::from("abc") )
);
println!("Success!")
} |
Beta Was this translation helpful? Give feedback.
-
再更新一个6的思路 trait MyTrait {
type Output;
fn f(&self) -> Self::Output;
}
impl MyTrait for u32 {
type Output = u32;
fn f(&self) -> Self::Output { 42 }
}
impl MyTrait for String {
type Output = String;
fn f(&self) -> Self::Output { self.clone() }
}
fn my_function<T: MyTrait<Output = T>> (
x: Box<dyn MyTrait<Output = T>>
) -> T { // could be discarded
x.f()
}
fn my_function_2<T: MyTrait<Output = T>> (
x: Box<T>
) -> T { // could be discarded
x.f()
}
fn main() {
my_function(
Box::new(13_u32)
);
my_function(
Box::new( String::from("abc") )
);
my_function_2(
Box::new(13_u32)
);
my_function_2(
Box::new( String::from("abc") )
);
println!("Success!")
} |
Beta Was this translation helpful? Give feedback.
-
来个花活,虽然编译过去了,但是应该属于静态的 // 通过特征对象实现以下函数, |
Beta Was this translation helpful? Give feedback.
-
第二题可以根据特征对象的学习内容 写成 let birds : Vec<Box> = vec![Box::new(Duck{}),Box::new(Swan{})];; |
Beta Was this translation helpful? Give feedback.
-
trait MyTrait {
fn f(&self) -> Self;
}
impl MyTrait for u32 {
fn f(&self) -> u32 { 42 }
}
impl MyTrait for String {
fn f(&self) -> String { self.clone() }
}
fn my_function(x: impl MyTrait) -> impl MyTrait {
x.f()
}
fn main() {
my_function(13_u32);
my_function(String::from("abc"));
} 第五题的这个为什么可以通过啊,my_function()不是返回了两种不同的类型(u32和String)吗 |
Beta Was this translation helpful? Give feedback.
-
10.4特征对象第5题,我有一种邪道做法hhh,把函数都设置为不返回值 // 使用至少两种方法让代码工作
// 不要添加/删除任何代码行
trait MyTrait {
fn f(&self);
}
impl MyTrait for u32 {
fn f(&self){ 42 ;}
}
impl MyTrait for String {
fn f(&self) { self.clone() ;}
}
fn my_function(x: Box<dyn MyTrait>) {
x.f();
}
fn main() {
my_function(Box::new(13_u32));
my_function(Box::new(String::from("abc")));
println!("Success!")
} |
Beta Was this translation helpful? Give feedback.
-
1、使用 trait Bird {
fn quack(&self) -> String;
}
struct Duck;
impl Duck {
fn swim(&self) {
println!("Look, the duck is swimming")
}
}
struct Swan;
impl Swan {
fn fly(&self) {
println!("Look, the duck.. oh sorry, the swan is flying")
}
}
impl Bird for Duck {
fn quack(&self) -> String{
"duck duck".to_string()
}
}
impl Bird for Swan {
fn quack(&self) -> String{
"swan swan".to_string()
}
}
fn main() {
// 填空
let duck = Duck;
duck.swim();
let bird = hatch_a_bird(2);
// 变成鸟儿后,它忘记了如何游,因此以下代码会报错
// bird.swim();
// 但它依然可以叫唤
assert_eq!(bird.quack(), "duck duck");
let bird = hatch_a_bird(1);
// 这只鸟儿忘了如何飞翔,因此以下代码会报错
// bird.fly();
// 但它也可以叫唤
assert_eq!(bird.quack(), "swan swan");
println!("Success!")
}
// 注意写法Box封装
fn hatch_a_bird(op:i32)->Box<dyn Bird>{
if op==1{
Box::new(Swan)
}else{
Box::new(Duck)
}
} 2、在数组中使用特征对象 trait Bird {
fn quack(&self);
}
struct Duck;
impl Duck {
fn fly(&self) {
println!("Look, the duck is flying")
}
}
struct Swan;
impl Swan {
fn fly(&self) {
println!("Look, the duck.. oh sorry, the swan is flying")
}
}
impl Bird for Duck {
fn quack(&self) {
println!("{}", "duck duck");
}
}
impl Bird for Swan {
fn quack(&self) {
println!("{}", "swan swan");
}
}
fn main() {
// 填空,这里必须要说明一下这个birds数组的类型是dyn不然其实在编辑器里面默认类型是vec<Box<Duck>>
let birds:Vec<Box<dyn Bird>>=vec![
Box::new(Duck),
Box::new(Swan)
];
for bird in birds {
bird.quack();
}
} 3、 一开始没有理解但是通过编译的版本: // 填空
trait Draw {
fn draw(&self) -> String;
}
impl Draw for u8 {
fn draw(&self) -> String {
format!("u8: {}", *self)
}
}
impl Draw for f64 {
fn draw(&self) -> String {
format!("f64: {}", *self)
}
}
fn main() {
let x = 1.1f64;
let y = 8u8;
// draw x
draw_with_box(Box::new(x));
// draw y
draw_with_ref(Box::new(y));
println!("Success!")
}
fn draw_with_box(x: Box<dyn Draw>) {
x.draw();
}
fn draw_with_ref(x: Box<dyn Draw>) {
x.draw();
} 做完第四题回头发现自己的荒唐的版本: // 填空
trait Draw {
fn draw(&self) -> String;
}
impl Draw for u8 {
fn draw(&self) -> String {
format!("u8: {}", *self)
}
}
impl Draw for f64 {
fn draw(&self) -> String {
format!("f64: {}", *self)
}
}
fn main() {
let x = 1.1f64;
let y = 8u8;
// draw x
draw_with_box(Box::new(x));
// draw y
draw_with_ref(&y);
println!("Success!")
}
fn draw_with_box(x: Box<dyn Draw>) {
x.draw();
}
fn draw_with_ref(x: &dyn Draw) {
x.draw();
} 4、静态分发和动态分发 trait Foo {
fn method(&self) -> String;
}
impl Foo for u8 {
fn method(&self) -> String { format!("u8: {}", *self) }
}
impl Foo for String {
fn method(&self) -> String { format!("string: {}", *self) }
}
// 通过泛型实现以下函数
fn static_dispatch<T:Foo>(x:T){
x.method();
}
// 通过特征对象实现以下函数
fn dynamic_dispatch(x:&dyn Foo){
x.method();
}
fn main() {
let x = 5u8;
let y = "Hello".to_string();
static_dispatch(x);
dynamic_dispatch(&y);
println!("Success!")
} 5、对象安全 我自己想到的比较简单的一种,移除 // 使用至少两种方法让代码工作
// 不要添加/删除任何代码行
trait MyTrait {
fn f(&self) ;
}
impl MyTrait for u32 {
fn f(&self) { 42; }
}
impl MyTrait for String {
fn f(&self) { self.clone(); }
}
fn my_function(x: Box<dyn MyTrait>) {
x.f()
}
fn main() {
my_function(Box::new(13_u32));
my_function(Box::new(String::from("abc")));
println!("Success!")
} 晕乎乎地看了答案 第一种,只要对象是实现了 // 使用至少两种方法让代码工作
// 不要添加/删除任何代码行
trait MyTrait {
fn f(&self) -> Self;
}
impl MyTrait for u32 {
fn f(&self) -> Self { 42 }
}
impl MyTrait for String {
fn f(&self) -> Self { self.clone() }
}
fn my_function(x: impl MyTrait)->impl MyTrait {
x.f()
}
fn main() {
my_function(13_u32);
my_function(String::from("abc"));
println!("Success!")
} 第二种,把所有 // 使用至少两种方法让代码工作
// 不要添加/删除任何代码行
trait MyTrait {
fn f(&self) -> Box<dyn MyTrait>;
}
impl MyTrait for u32 {
fn f(&self) -> Box<dyn MyTrait>{
Box::new(42)
}
}
impl MyTrait for String {
fn f(&self) -> Box<dyn MyTrait>{
Box::new(self.clone())
}
}
fn my_function(x: Box<dyn MyTrait>) -> Box<dyn MyTrait> {
x.f()
}
fn main() {
my_function(Box::new(13_u32));
my_function(Box::new(String::from("abc")));
println!("Success!")
} |
Beta Was this translation helpful? Give feedback.
-
第二题 三种方式: let birds:Vec<&dyn Bird> = vec![&Duck, &Swan] let birds:Vec<Box<dyn Bird>>=vec![Box::new(Duck),Box::new(Swan)] let birds:[Box<dyn Bird>;2] = [Box::new(Duck), Box::new(Swan)] |
Beta Was this translation helpful? Give feedback.
-
第5题
trait MyTrait<T> {
fn f(&self) -> T;
}
impl MyTrait<u32> for u32 {
fn f(&self) -> u32 { 42 }
}
impl MyTrait<String> for String {
fn f(&self) -> String { self.clone() }
}
fn my_function<T>(x: Box<dyn MyTrait<T>>) -> T {
x.f()
}
fn main() {
my_function(Box::new(13_u32));
my_function(Box::new(String::from("abc")));
println!("Success!")
}
trait MyTrait {
fn f(&self) -> Self;
}
impl MyTrait for u32 {
fn f(&self) -> Self { 42 }
}
impl MyTrait for String {
fn f(&self) -> Self { self.clone() }
}
fn my_function(x: impl MyTrait) -> impl MyTrait {
x.f()
}
fn main() {
my_function(13_u32);
my_function(String::from("abc"));
println!("Success!")
} |
Beta Was this translation helpful? Give feedback.
-
第五题的官方题解:
|
Beta Was this translation helpful? Give feedback.
-
没太懂 为什么第二题这样写就不行
|
Beta Was this translation helpful? Give feedback.
-
Done。最后一题,如果只考虑我们目前已经学过的方法,那么就是
题解将 dyn 变成泛型。虽然违反了第二条规定,但是我们只要避免使用 dyn 即可——将所有函数都改成泛型实现。 trait MyTrait {
fn f(&self) -> Self;
}
impl MyTrait for u32 {
fn f(&self) -> Self { 42 }
}
impl MyTrait for String {
fn f(&self) -> Self { self.clone() }
}
fn my_function (x: impl MyTrait ) -> impl MyTrait {
x.f()
}
fn main() {
my_function(13_u32);
my_function(String::from("abc"));
println!("Success!")
} 返回 Box 而不是 Self从而避免违反第一条规定。 trait MyTrait {
fn f(&self) -> Box<dyn MyTrait>;
}
impl MyTrait for u32 {
fn f(&self) -> Box<dyn MyTrait> { Box::new(42) }
}
impl MyTrait for String {
fn f(&self) -> Box<dyn MyTrait> { Box::new(self.clone()) }
}
fn my_function (x: &dyn MyTrait ) -> Box<dyn MyTrait> {
x.f()
}
fn main() {
my_function(&13_u32);
my_function(&String::from("abc"));
println!("Success!")
} |
Beta Was this translation helpful? Give feedback.
-
帮忙解答下这里是什么错误? &self.clone() 的类型和 self 的类型都是 &String,为什么clone的string取引用会报错? // 使用至少两种方法让代码工作
// 不要添加/删除任何代码行
trait MyTrait {
fn f(&self) -> &dyn MyTrait;
}
impl MyTrait for u32 {
fn f(&self) -> &dyn MyTrait { &42 }
}
impl MyTrait for String {
fn f(&self) -> &dyn MyTrait {
// &self.clone() // 这里会失败 returns a value referencing data owned by the current function
self // 这里却可以
}
}
fn my_function(x: &dyn MyTrait) -> &dyn MyTrait {
x.f()
}
fn main() {
my_function(&13_u32);
my_function(&String::from("abc"));
println!("Success!")
} |
Beta Was this translation helpful? Give feedback.
-
generics-traits/trait-object
Learn Rust with Example, Exercise and real Practice, written with ❤️ by https://course.rs team
https://practice.rs/generics-traits/trait-object.html
Beta Was this translation helpful? Give feedback.
All reactions