代码之家  ›  专栏  ›  技术社区  ›  Tim Diekmann suresh madaparthi

为什么trait对象上的函数在以“Self:size”为界时不能调用?

  •  3
  • Tim Diekmann suresh madaparthi  · 技术社区  · 6 年前

    我有以下代码:

    trait Bar {
        fn baz(&self, arg: impl AsRef<str>) where Self: Sized;
    }
    
    struct Foo;
    
    impl Bar for Foo {
        fn baz(&self, arg: impl AsRef<str>) {}
    }
    
    fn main() {
        let boxed: Box<dyn Bar> = Box::new(Foo);
        boxed.baz();
    }
    

    playground

    error: the `baz` method cannot be invoked on a trait object
      --> src/main.rs:13:11
       |
    13 |     boxed.baz();
       |           ^^^
    

    为什么这不可能?它在移除 Self: Sized 然而,绑定之后,我就不能使用泛型了,这对调用方来说是相当舒服的。


    这是 副本 Why does a generic method inside a trait require trait object to be sized? . 这个问题问你为什么不能打电话 baz 从一个特征对象。我是 discussed .

    2 回复  |  直到 6 年前
        1
  •  3
  •   Phoenix    6 年前

    因为铁锈的仿制药系统是通过单菌根作用的。

    诸如Rub和C++之类的语言使用泛型的单形化。对于类型参数的每个组合,调用一个泛型函数,生成专门的机器代码,用这些类型参数组合运行该函数。功能是 . 这允许将数据存储在适当的位置,消除了转换的成本,并允许泛型代码对该类型参数调用“静态”函数。

    许多语言中的Trait对象(包括Rust)都是使用 函数表 垂直入口 . vtable条目是存储在不可变内存区域中的函数指针的集合,这些指针指向该特性方法的实现。因此,当对trait对象调用方法时,它会在vtable中查找实现的函数指针,然后间接跳转到该指针。

    不幸的是,如果Rust编译器在编译时不知道实现该函数的代码,它就不能单形化函数,这就是在trait对象上调用方法时的情况。因此,不能对trait对象调用泛型函数(好吧,泛型覆盖类型)。

    -编辑-

    听起来你在问为什么 : Sized

    :大小

    然而,Rust试图明确编译器正在做的事情,而这些隐式方法将与之背道而驰。对于初学者来说,尝试在trait对象上调用泛型函数而使其无法编译难道不是一件令人困惑的事情吗?

    相反,锈让你 明确地

    trait Foo: Sized {

    或者 明确地 使某些函数仅在静态分派时可用

    fn foo<T>() where Self: Sized {

        2
  •  0
  •   Tim Diekmann suresh madaparthi    6 年前

    绑定使方法不安全。不是对象安全的特征不能用作类型。

    采取的方法 Self 自我 或其他要求 Self: Sized 对象不安全。这是因为trait对象上的方法是通过动态分派调用的,而trait实现的大小在编译时无法知道。-- Peter Hall

    引用 official docs

    只有对象安全的特征才可以成为特征对象。如果这两种情况都是真的,则特征是对象安全的:

    • 这个特点不需要

    那么什么使方法对象安全呢?每种方法都必须要求 或以下所有情况:

    • 不得使用 自我

    另见: