为什么rust编译器需要选项<;的类型注释&;impl Trait>;?

为什么rust编译器需要选项<;的类型注释&;impl Trait>;?,rust,Rust,鉴于此MCVE: fn main() { println!("{}", foo(None)); } trait Trait {} struct Struct {} impl Trait for Struct {} fn foo(maybe_trait: Option<&impl Trait>) -> String { return "hello".to_string(); } 使用类型注释可使此编译: fn main() { let not

鉴于此MCVE:

fn main() {
    println!("{}", foo(None));
}

trait Trait {}
struct Struct {}
impl Trait for Struct {}

fn foo(maybe_trait: Option<&impl Trait>) -> String {
    return "hello".to_string();
}
使用类型注释可使此编译:

fn main() {
    let nothing: Option<&Struct> = None;
    println!("{}", foo(nothing));
}

trait Trait {}
struct Struct {}
impl Trait for Struct {}

fn foo(maybe_trait: Option<&impl Trait>) -> String {
    return "hello".to_string();
}
我理解为“你不应该在这里使用特征,因为那样我就不知道我需要为这个参数分配多少内存”

但是当我通过
None

当然,对于编译器来说,传递实现
Trait
(即
Struct
)的类型的任何具体实例都是可以的


旁注:
我已经了解了
&dyn Trait
&impl Trait
之间的区别。我不确定何时使用哪个,但由于我的程序确实使用
&impl Trait
进行编译(如上所述使用类型注释时),因此这似乎是一个安全的选择

如果我们改为将函数参数的类型设置为
Option
,则我的程序编译时在
main()
中没有类型注释:

fn main() {
    println!("{}", foo(None));
}

trait Trait {}
struct Struct {}
impl Trait for Struct {}

fn foo(maybe_trait: Option<&dyn Trait>) -> String {
    return "hello".to_string();
}
这:

这意味着有一个函数
foo
,该函数的选项包含指向实现
Trait
的某个类型的胖指针。如果在函数内部调用
maybe\u trait
上的某个方法,则调用将通过动态分派进行

因为只有一个函数
foo
,所以在使用
None
时,您不必对类型做任何说明,只有一个函数


但是动态调度是有代价的——这一函数没有针对任何特定的
T
进行优化,它可以动态地处理每个
T

这是因为编译器必须推断类型,即使只有一个可以猜测,它也无法猜测它们(除非在某些特定的场景中不包括这一个)<代码>无可以是
选项::无
选项:::无
<处于参数位置的code>impl trait与泛型类似,因此编译器必须知道要实例化的
foo
版本,并且
None
可以是任何版本。例如,请参见(所有答案)和。其中一个选项是否回答了您的问题,或者您仍然不确定?这很重要,选项的大小取决于实现该特性的类型。我认为您缺少了
foo::HugeThing
可能与
foo::OtherThing
行为不同,即使在传递
None
时,编译器也必须知道如何使用正确的选项。(此外,并非所有引用的大小都相同,因为对未大小的类型的引用都是胖指针,但即使它们是胖指针,编译器也不会为您选择类型。)谢谢!再加上@Trentl的评论,这太完美了。在接受之前,我会稍等片刻,这样他也会有机会写一个答案,因为他也解释了一些好的观点well@lucidbrot谢谢,但除非我的评论中有什么重要的东西你认为在这个回答中没有解释,否则我会让michalsrb不要他勾选:)很高兴我能帮忙!这终于让它为我点击,伟大的答案。
warning: trait objects without an explicit `dyn` are deprecated
 --> src\main.rs:2:26
  |
2 |     let nothing: Option<&Trait> = None;
  |                          ^^^^^ help: use `dyn`: `dyn Trait`
  |
  = note: #[warn(bare_trait_objects)] on by default

error[E0277]: the size for values of type `dyn Trait` cannot be known at compilation time
 --> src\main.rs:3:20
  |
3 |     println!("{}", foo(nothing));
  |                    ^^^ doesn't have a size known at compile-time
  |
  = help: the trait `std::marker::Sized` is not implemented for `dyn Trait`
  = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
note: required by `foo`
 --> src\main.rs:10:1
  |
10| fn foo(maybe_trait: Option<&impl Trait>) -> String {
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to previous error

For more information about this error, try `rustc --explain E0277`.
fn main() {
    println!("{}", foo(None));
}

trait Trait {}
struct Struct {}
impl Trait for Struct {}

fn foo(maybe_trait: Option<&dyn Trait>) -> String {
    return "hello".to_string();
}
$ cargo --version
cargo 1.37.0 (9edd08916 2019-08-02)  

$ cat Cargo.toml
[package]
name = "rdbug"
version = "0.1.0"
authors = ["redacted"]
edition = "2018"
fn foo(maybe_trait: Option<&impl Trait>) -> String {
fn foo<T: Trait>(maybe_trait: Option<&T>) -> String {