< 返回版块

kaixinbaba 发表于 2020-12-11 10:47

Tags:trait,泛型


trait Action {
    fn act(&self);
}

struct DefaultAction {
    content: String,
}

impl Action for DefaultAction {
    fn act(&self) {
        println!("do {}", self.content);
    }
}

struct User {
    action: Action,
}

impl User {

    pub fn user_act(&self) {
        self.action.act()
    }
}

fn main() {
    let action = DefaultAction {
        content: "hello Rust".to_string(),
    };
    let user = User {
        action,
    };
    user.user_act();
}

这是模拟我最初的想法,差不多就是一个结构体中需要包含一个实现了某一 trait 的成员,通过委派给该成员对应的方法,实现类似 Java 中设计模式的概念,但是编译器提示报错,关键是我无论怎么改都改不好,所以来求助了。 在 Java 中是很常见的,对象的一个字段是一个接口。我想知道类似的功能在 Rust 中怎么实现,谢谢大家

评论区

写评论
作者 kaixinbaba 2020-12-11 14:59

谢谢你的回复

--
👇
HuangJinAmm: https://doc.rust-lang.org/book/ch17-01-what-is-oo.html

官方的教程里就有类似的例子

作者 kaixinbaba 2020-12-11 14:58

SOGO 谢谢~

--
👇
caohaiwd: java 的对象都是引用来表达的,引用具有确定的编译时大小,所以可以那么写。rust 里面也需要用指针的方式,如 Box

作者 kaixinbaba 2020-12-11 14:58

好的 谢谢

--
👇
dollarkillerx: dyn告诉编译器这个不用知道实现Action这个trait的具体类型 在运行时去判度 会有运行时开销

你可以阅读下动态分发 和静态分发

👇
kaixinbaba: 这个 Box 的写法和前一位大佬的泛型的区别在哪里 求问?我理解是 泛型 相当于告诉 Rust编译器 具体的类型,最终Rust编译器会转成具体的类型,而Box的话是告诉编译器这个成员 你不用管之后内存的释放会由Box来管理? 是这样吗。。

caohaiwd 2020-12-11 13:54

java 的对象都是引用来表达的,引用具有确定的编译时大小,所以可以那么写。rust 里面也需要用指针的方式,如 Box

WorldLink 2020-12-11 13:11

动态分发

trait Action {
    fn act(&self);
}

struct DefaultAction {
    content: String,
}

impl Action for DefaultAction {
    fn act(&self) {
        println!("do {}", self.content);
    }
}

struct User<'a> {
    action: &'a dyn Action,
}

impl<'a> User<'a> {
    pub fn user_act(&self) {
        self.action.act()
    }
}

fn test2() {
    let action = DefaultAction {
        content: "hello Rust".to_string(),
    };
    let user = User {
        action: &action,
    };
    user.user_act();
}

静态分发:

trait Action {
    fn act(&self);
}

struct DefaultAction {
    content: String,
}

impl Action for DefaultAction {
    fn act(&self) {
        println!("do {}", self.content);
    }
}

struct User<T> {
    action: T,
}

impl<T: Action> User<T> {
    pub fn user_act(&self) {
        self.action.act()
    }
}

fn test2() {
    let action = DefaultAction {
        content: "hello Rust".to_string(),
    };
    let user = User {
        action,
    };
    user.user_act();
}

动态分发 会产生运行时 开销(寻值) 静态分发 性能高 二进值文件回膨胀

HuangJinAmm 2020-12-11 12:31

https://doc.rust-lang.org/book/ch17-01-what-is-oo.html

官方的教程里就有类似的例子

WorldLink 2020-12-11 11:49

看看这篇https://zhuanlan.zhihu.com/p/163650432

WorldLink 2020-12-11 11:48

dyn告诉编译器这个不用知道实现Action这个trait的具体类型 在运行时去判度 会有运行时开销

你可以阅读下动态分发 和静态分发

👇
kaixinbaba: 这个 Box 的写法和前一位大佬的泛型的区别在哪里 求问?我理解是 泛型 相当于告诉 Rust编译器 具体的类型,最终Rust编译器会转成具体的类型,而Box的话是告诉编译器这个成员 你不用管之后内存的释放会由Box来管理? 是这样吗。。

作者 kaixinbaba 2020-12-11 11:44

感觉泛型的写法比较麻烦,前一位大佬的Box的写法,比较符合我的心智模型,虽然我其实并不十分清楚,两者的区别,谢谢你的回复

--
👇
shaitao: 年轻人不讲泛型, rust的静态分配在编译的时候就要把类型确定下来的

trait Action {
    fn act(&self);
}

struct DefaultAction {
    content: String,
}

impl Action for DefaultAction {
    fn act(&self) {
        println!("do {}", self.content);
    }
}

struct User<T> {
    action: T,
}

impl<T:Action> User<T> {
    pub fn user_act(&self) {
        Action::act(&self.action)
    }
}

fn main() {
    let action = DefaultAction {
        content: "hello Rust".to_string(),
    };
    let user = User {
        action,
    };
    user.user_act();
}
作者 kaixinbaba 2020-12-11 11:43

这个 Box 的写法和前一位大佬的泛型的区别在哪里 求问?我理解是 泛型 相当于告诉 Rust编译器 具体的类型,最终Rust编译器会转成具体的类型,而Box的话是告诉编译器这个成员 你不用管之后内存的释放会由Box来管理? 是这样吗。。

--
👇
dollarkillerx:

trait Action {
	fn act(&self);
}

struct DefaultAction {
	content: String,
}

impl Action for DefaultAction {
	fn act(&self) {
		println!("do {}", self.content);
	}
}

struct User {
	action: Box<dyn Action>,
}

impl User {
	pub fn user_act(&self) {
		self.action.act()
	}
}

fn main() {
	let action = DefaultAction {
		content: "hello Rust".to_string(),
	};
	let user = User {
		action: Box::new(action)
	};
	user.user_act();
}
   Compiling test_c v0.1.0 (/home/wangy/mvalley/quick-search/test_c)
    Finished dev [unoptimized + debuginfo] target(s) in 0.52s
     Running `target/debug/test_c`
do hello Rust
WorldLink 2020-12-11 11:35
trait Action {
	fn act(&self);
}

struct DefaultAction {
	content: String,
}

impl Action for DefaultAction {
	fn act(&self) {
		println!("do {}", self.content);
	}
}

struct User {
	action: Box<dyn Action>,
}

impl User {
	pub fn user_act(&self) {
		self.action.act()
	}
}

fn main() {
	let action = DefaultAction {
		content: "hello Rust".to_string(),
	};
	let user = User {
		action: Box::new(action)
	};
	user.user_act();
}
   Compiling test_c v0.1.0 (/home/wangy/mvalley/quick-search/test_c)
    Finished dev [unoptimized + debuginfo] target(s) in 0.52s
     Running `target/debug/test_c`
do hello Rust
shaitao 2020-12-11 11:24

年轻人不讲泛型, rust的静态分配在编译的时候就要把类型确定下来的

trait Action {
    fn act(&self);
}

struct DefaultAction {
    content: String,
}

impl Action for DefaultAction {
    fn act(&self) {
        println!("do {}", self.content);
    }
}

struct User<T> {
    action: T,
}

impl<T:Action> User<T> {
    pub fn user_act(&self) {
        Action::act(&self.action)
    }
}

fn main() {
    let action = DefaultAction {
        content: "hello Rust".to_string(),
    };
    let user = User {
        action,
    };
    user.user_act();
}
作者 kaixinbaba 2020-12-11 10:48

error[E0308]: mismatched types
  --> src/main.rs:31:9
   |
31 |         action,
   |         ^^^^^^ expected trait object `dyn Action`, found struct `DefaultAction`
   |
   = note: expected trait object `(dyn Action + 'static)`
                    found struct `DefaultAction`

error[E0277]: the size for values of type `(dyn Action + 'static)` cannot be known at compilation time
  --> src/main.rs:30:16
   |
30 |       let user = User {
   |  ________________^
31 | |         action,
32 | |     };
   | |_____^ doesn't have a size known at compile-time
   |
   = help: within `User`, the trait `Sized` is not implemented for `(dyn Action + 'static)`
   = note: required because it appears within the type `User`
   = note: structs must have a statically known size to be initialized

error[E0277]: the size for values of type `(dyn Action + 'static)` cannot be known at compilation time
  --> src/main.rs:30:9
   |
30 |     let user = User {
   |         ^^^^ doesn't have a size known at compile-time

这是现在的编译错误提示

1 共 13 条评论, 1 页