我有一个函数,它返回我想从另一个trait中的方法调用的impl Stream.这里有一个非常粗略的例子,说明我正在努力实现的目标:

struct Example<S>
where
    S: Stream<Item = String>,
{
    phantom: std::marker::PhantomData<S>,
}

trait Thing<S> {
    fn go(self) -> S;
}

impl<S> Thing<S> for Example<S>
where
    S: Stream<Item = String>,
{
    fn go(self) -> S {
        the_stream()
    }
}

fn the_stream() -> impl Stream<Item = String> {
    stream::unfold(0, |i| async move { Some((i.to_string(), i + 1)) })
}

这会产生错误:

期望的类型参数S发现不透明的类型impl Stream<Item = String>

类型参数S具有与返回类型the_stream相同的约束,但是编译器无法匹配它们.我显然对不透明类型如何映射到类型参数缺乏一些理解.我可以做些什么来帮助编译器,让代码在不对流进行装箱的情况下运行?

推荐答案

虽然它们都实现相同的trait,但类型Simpl Stream<Item = String>实际上是不同的类型.使用泛型类型参数,函数的调用方可以确定所需的具体类型.但对于不透明的类型参数,他们无法指定,用户所知道的就是存在实现它的某个类型. 请考虑以下示例:

use std::collections::HashSet;
fn generic<A: FromIterator<u8>>() -> A {
    (1..9).collect()
}

fn existential() -> impl FromIterator<u8> + std::fmt::Debug {
    (1..9).collect::<Vec<_>>()
}

fn main() {
    let v: Vec<_> = generic();
    let s: HashSet<_> = generic();
    dbg!(v, s);
    let e = existential();
    dbg!(e);
}

函数generic可以返回我们想要的实现FromIterator<u8>的任何类型,存在的那个总是产生Vec<u8>,但我们甚至不能假设,我们可以使用的是我们指定的特征,即FromIterator<u8>,它实际上不允许我们对该类型做任何事情.出于演示目的,我还添加了Debug特征,这样我们就可以判断existential的输出

没有办法用existential来定义generic,因为Existential只能返回相同的类型,而generic必须产生请求的类型.

Rust相关问答推荐

有条件默认实现

将此字符串转换为由空格字符分隔的空格

何时可以在Rust中退出异步操作?

在Rust中赋值变量有运行时开销吗?

MutexGuard中的过滤载体不需要克隆

这种获取-释放关系是如何运作的?

如何向下转换到MyStruct并访问Arc Mutex MyStruct实现的方法?

定义只有一些字段可以缺省的 struct

JSON5中的变量类型(serde)

写入引用会更新基础值,但引用会打印意外的值

如何在Rust中缩短数组

如何初始化选项<;T>;数组Rust 了?

有没有一种方法可以创建一个闭包来计算Rust中具有随机系数的n次多项式?

Rust 中的内存管理

注释闭包参数强调使用高阶排定特征界限

特征中定义的类型与一般定义的类型之间的区别

如何存储返回 Future 的闭包列表并在 Rust 中的线程之间共享它?

在 Rust 中返回对枚举变体的引用是个好主意吗?

HashMap entry() 方法使borrow 的时间比预期的长

为什么一个整型变量赋值给另一个变量后仍然可以使用?