返回介绍

8.3.2 传递

发布于 2024-10-13 11:25:30 字数 3079 浏览 0 评论 0 收藏 0

特征对象(trait object)通常以指针形式出现。

A trait object is a pointer to some value that implements a given trait.

&dyn Trait     // trait object

Box<dyn Trait>
Rc<dyn Trait>
Arc<dyn Trait>
 trait object
+------------+      +------------+  
| dptr   --|----------> | data ...   |
+------------+      +------------+
| vptr     |
+----------|-+      +------------+  
       |        | destructor |
       +------------> +------------+
              | size     |
              +------------+  vtable
              | alignment  |
              +------------+
              | method[0]  |
              +------------+
              | ...    |
              +------------+
use std::any::Any;

trait TestTrait {
  fn test(&self);
  fn as_any(&self) -> &dyn Any;  
}

impl TestTrait for i32 {
  fn test(&self) { println!("{:?}", *self); }
  fn as_any(&self) -> &dyn Any { self }
}

/* ------------------------------------------*/

fn main() {
  let n = 123;

  // to trait.
  let x: &dyn TestTrait = &n;
  x.test();

  // downcast.
  let i: &i32 = x.as_any().downcast_ref::<i32>().expect("err");
  println!("{:?}", i);

  // box.
  let b = Box::new(x);
  b.test();

  // vec.
  let v = vec![x];
  v[0].test();
}

不能以特征变量访问目标类型成员。(不同于实现块内 Selfself

trait TestTrait {
  fn test(&self) { println!("test"); }
}

struct Data {
  n: i32
}

impl Data {
  fn haha(&self) { println!("haha!"); }
}

impl TestTrait for Data {}

/* ------------------------------------------*/

fn main() {
  let d = Data{ n: 100 };
  d.test();          // 扩展。
  d.haha();          // 方法。
  assert_eq!(d.n, 100);    // 字段。

  let x: &dyn TestTrait = &d;
  x.test();          // 特征成员。

  // x.haha();
  //   ^^^^ method not found in `&dyn TestTrait`

  // assert_eq!(x.n, 100);
  //        ^ no field `n` on type `&dyn TestTrait`
}

特征对象不支持关联函数调用,另须添加 Self: Sized 约束(表明编译期大小已知)。

trait TestTrait {
  fn new(n: i32) -> Self
    where Self: Sized;  // !!!
}

struct Data {
  n: i32
}

impl TestTrait for Data {
  fn new(n: i32) -> Self {
    Data{ n }
  }  
}

/* ------------------------------------------*/

fn main() {

  // TestTrait::new(100);
  // ^^^^^^^^^^^^^^ cannot call associated function of trait
  
  let _t: &dyn TestTrait = &Data::new(100);
}

作为参数和返回值传递,以及泛型(约束)版本。

trait TestTrait {
  fn test(&self) { println!("test"); }
}

impl TestTrait for i32 {}

/* ------------------------------------------*/

// 动态分发。
fn test(x: &dyn TestTrait) -> &dyn TestTrait {   
  x.test();
  x
}

// 泛型化:静态分发,参数和返回值。
fn test2(x: impl TestTrait) -> impl TestTrait {   
  x.test();
  x
}

fn main() {
  let x = 123;

  let t = test(&x);  // 自动将参数转换为特征对象。
  t.test();

  test2(x);
}
fn test<T>(x: &T) -> &T where T: TestTrait{   
  x.test();
  x
}

fn main() {
  let t = test(&123);
  t.test();
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文