为什么在通用使用时调用特征方法不会调用同名的固有方法?

Fab*_*aro 2 generics traits rust

我是 Rust 新手,我在通用函数中有一个奇怪的行为以及一些关于它的问题。我理解结果,但不知道这是否正常:

trait A {
    fn a() {
        println!("Oh Noooo...");
    }
    fn b();
}

struct SA {}

impl SA {
    fn a() {
        println!("sa");
    }

    fn b() {
        println!("b");
    }
}

impl A for SA {
    fn b() {
        println!("b2");
    }
}

fn foo<T>() where T: A {
    T::a();
    // <T as T>::a(); // -> Generate an error a not in T
}

fn bar<T>() where T: A {
    T::b();
    // <T as T>::b(); // -> Generate an error b not in T
}

fn main() {
    //<SA as SA>::a(); // -> Generate an error not found in SA
    SA::a();
    foo::<SA>();
    SA::b();
    bar::<SA>();
}
Run Code Online (Sandbox Code Playgroud)
trait A {
    fn a() {
        println!("Oh Noooo...");
    }
    fn b();
}

struct SA {}

impl SA {
    fn a() {
        println!("sa");
    }

    fn b() {
        println!("b");
    }
}

impl A for SA {
    fn b() {
        println!("b2");
    }
}

fn foo<T>() where T: A {
    T::a();
    // <T as T>::a(); // -> Generate an error a not in T
}

fn bar<T>() where T: A {
    T::b();
    // <T as T>::b(); // -> Generate an error b not in T
}

fn main() {
    //<SA as SA>::a(); // -> Generate an error not found in SA
    SA::a();
    foo::<SA>();
    SA::b();
    bar::<SA>();
}
Run Code Online (Sandbox Code Playgroud)

游乐场链接

我的问题是关于“哦,不……”。我知道代码不是常规的,函数a()不在 the 中impl A for SA,但是为什么在通用函数中,不是在调用的a()in 中?SA我认为该where子句只是对我的结构实现特征这一事实的限制。看起来好像 theT被转换成 a dyn A,是这样吗?

为什么当我想在约束确保存在的情况<T as T>下强制调用时会出现错误?wherea

我的问题是在更复杂的情况下,该函数a()是由我的块中函数的属性宏生成的impl SA,我不知道如何在impl块外生成该函数以及是否可能。是为整个impl块实现宏的唯一解决方案吗?

Kev*_*eid 5

\n

我知道代码不常规,函数 a 不在中,impl A for SA但为什么在通用函数中,调用的不是 SA 中的 a 。

\n
\n

泛型函数 ( ) 中的名称解析foo基于调用该函数的具体类型,而基于定义时的类型和特征。当编译器处理

\n
fn foo<T>() where T: A {\n    T::a();\n}\n
Run Code Online (Sandbox Code Playgroud)\n

它用来查找的唯一信息是实现. 因此,它相当于or ,调用 Trait 方法。aTTAA::a()<T as A>::a()

\n

这不仅仅是一个任意的选择,而是 Rust 设计 \xe2\x80\x94 的一个重要部分,即通用函数的工作原理完全相同,无论任何命名冲突或它所使用的类型的其他附带细节如何。要了解如果 Rust 工作方式不同,我们如何会收到错误,请考虑以下程序:

\n
trait A {\n    fn a(x: i32);\n}\n\nstruct SA {}\n\nimpl SA {\n    fn a(x: &str) {}\n}\n\nfn foo<T>() where T: A {\n    T::a("hello world");\n}\n
Run Code Online (Sandbox Code Playgroud)\n

特征函数A::a采用&str,但固有函数SA::a采用i32。如果名称解析决定应选择固有函数(如果可用),那么foo::<SA>()即使通用函数定义本身没问题,也会出现类型错误。这很糟糕,因为这意味着泛型函数可能会仅仅因为类型具有特定的关联函数名称而失败。并且,这将是一个 \xe2\x80\x9cpost-monomorphization 错误 \xe2\x80\x9d \xe2\x80\x94 泛型函数的定义无法被认为是有效的(类型检查等),除非它的每次用法的上下文。这会产生难以调试的问题,并且还会减慢编译速度,因为需要更多的检查。

\n
\n

为了避免这个问题,您应该将固有关联函数视为本质上与特征关联函数位于不同的命名空间中。你不能简单地通过给泛型函数一个匹配的名称 \xe2\x80\x94 来调用固有函数,泛型函数调用特征函数(当涉及类型变量时;当然,泛型函数可以调用关联函数的固有函数)类型)。

\n
\n

我认为 where 只是对我的结构实现特征这一事实的限制。

\n
\n

是的,但问题是你的泛型函数将永远无法调用固有的SA::a(),除非它明确提到该具体类型。这并不是说该where子句被隐藏了 SA::a(),而是SA::a() 根本不可能与之相关T

\n