我一直在用Rust 来混淆特性,我遇到了一个问题.以下是一些代码:

struct Foo;

trait Bar {}

impl Bar for Foo {}

fn bar<B: Bar>(bar: B) {}

fn barr<B: Bar>() {
    bar(Foo); // 1. THIS WILL WORK
    let foo: B = Foo; // 2. THIS WILL NOT WORK
    let foo_vec: Vec<B> = vec![Foo]; // 3. THIS WILL NOT WORK
}

这会产生以下错误:

error[E0308]: mismatched types
  --> src/main.rs:11:18
   |
11 |     let foo: B = Foo; // 2. THIS WILL NOT WORK
   |                  ^^^ expected type parameter, found struct `Foo`
   |
   = note: expected type `B`
              found type `Foo`

error[E0308]: mismatched types
  --> src/main.rs:12:32
   |
12 |     let foo_vec: Vec<B> = vec![Foo]; // 3. THIS WILL NOT WORK
   |                                ^^^ expected type parameter, found struct `Foo`
   |
   = note: expected type `_`
              found type `Foo`

为什么#2&amp#3.工作?我怎样才能让编译器知道Foo实际上有Bar impl呢?


另一个例子:

struct Foo<B: Bar> {
    bar: Option<B>,
}

struct Foo2;

trait Bar {}

impl<B: Bar> Bar for Foo<B> {}

impl Bar for Foo2 {}

fn bar<B: Bar>(bar: B) {}

fn circle_vec<B: Bar>() {
    bar(Foo2); // 1. WORKS
    Foo { bar: Some(Foo { bar: None }) }; // 2. WILL NOT WORK
}

这将给我带来以下错误:

error[E0282]: type annotations needed
  --> src/main.rs:17:21
   |
17 |     Foo { bar: Some(Foo { bar: None }) }; // 2. WILL NOT WORK
   |                     ^^^ cannot infer type for `B`

推荐答案

你有两个不同的问题,所以我想我会写两个不同的答案.


在第一个代码示例中,2和3不起作用,因为B是input类型的参数;是barr的呼叫者决定了B是什么.然而,你试图强迫它是Foo.

假设我们有另一个Bar的实现:

struct Quux;

impl Bar for Quux {}

假设我们这样称呼barr:

barr::<Quux>()

barr基本上是这样汇编的:

fn barr() {
    bar(Foo);
    let foo: Quux = Foo;
    let foo_vec: Vec<Quux> = vec![Foo];
}

FooQuux不兼容,Vec<Foo>Vec<Quux>也不兼容.

如果你试图创建一个包含任意Bar个对象的向量,你需要以非通用的方式使用Bar.由于特征类型没有大小,所以不能直接存储在Vec中,所以必须使用Vec<Box<Bar>>Vec<&Bar>或其他类型来包装指针.

fn barr() {
    bar(Foo);
    let foo: Box<Bar> = Box::new(Foo);
    let foo_vec: Vec<Box<Bar>> = vec![Box::new(Foo) as Box<Bar>];
}

在第二个代码示例中,错误是None的类型为Option<T>,而编译器无法推断T的适当类型.我们可以这样明确地指定T:

fn circle_vec<B: Bar>() {
    bar(Foo2);
    Foo {
        bar: Some(Foo { bar: None::<Foo2> }),
    };
}

Rust相关问答推荐

如何在不安全的代码中初始化枚举 struct

如何从Rust记录WASM堆内存使用情况?

在没有引用计数或互斥锁的情况下,可以从Rust回调函数内的封闭作用域访问变量吗?

如何使用 list 在Rust for Windows中编译?

有没有办法指定只在Rust的测试中有效的断言?

我无法理解Rust范围的定义(Rust Programming Language,第二版克拉布尼克和尼科尔斯)

不能在Rust中使用OpenGL绘制三角形

这是什么:`impl Trait for T {}`?

如何在 `connect_activate()` 之外创建一个 `glib::MainContext::channel()` 并将其传入?

可选包装枚举的反序列化

当锁被释放时,将锁包装到作用域中是否会发生变化?

pyO3 和 Panics

使用 Rust 从 Raspberry Pi Pico 上的 SPI 读取值

Rust 异步和 AsRef 未被发送

无法把握借来的价值不够长寿,请解释

为什么基于 clap::Parser 读取的大量数字进行计算比硬编码该数字时慢?

通用函数中的生命周期扣除和borrow (通用测试需要)

制作嵌套迭代器的迭代器

传递 Option<&mut T> 时何时需要 mut

Rust 生命周期:不能在方法内重新borrow 可变字段