我正在尝试获得一个随机数生成器。由于OsRng::new()
可能会失败,因此如果需要,我想退回到thread_rng()
:
extern crate rand; // 0.6.5
use rand::{rngs::OsRng, thread_rng, RngCore};
fn rng() -> impl RngCore {
match OsRng::new() {
Ok(rng) => rng,
Err(e) => thread_rng(),
}
}
但是,我收到了我无法理解的错误消息:
error[E0308]: match arms have incompatible types
--> src/lib.rs:6:5
|
6 | / match OsRng::new() {
7 | | Ok(rng) => rng,
8 | | Err(e) => thread_rng(),
| | ------------ match arm with an incompatible type
9 | | }
| |_____^ expected struct `rand::rngs::OsRng`, found struct `rand::prelude::ThreadRng`
|
= note: expected type `rand::rngs::OsRng`
found type `rand::prelude::ThreadRng`
为什么编译器期望rand::OsRng
而不是RngCore
的实现?如果我删除match
并直接返回thread_rng()
,我不会得到以上错误消息。
我不认为这是How do I return an instance of a trait from a method?的重复,因为另一个问题是关于如何可以从函数返回特征的问题,而这个问题是关于为什么,编译器不允许我返回特征,但希望我返回OsRng
,这不是函数的返回类型。
答案 0 :(得分:9)
impl Trait
不等同于返回接口或基类对象。这是说“我不想写我要返回的特定类型的名称”的一种方式。您仍在返回单个特定类型的值。您只是不说哪种类型。
每个分支都返回不同的类型,因此出现了问题。仅仅实现相同的特征是不够的。
在这种情况下,您可能想要的是特征对象,例如Box<dyn RngCore>
。
extern crate rand; // 0.6.5
use rand::{rngs::OsRng, thread_rng, RngCore};
fn rng() -> Box<dyn RngCore> {
match OsRng::new() {
Ok(rng) => Box::new(rng),
Err(_) => Box::new(thread_rng()),
}
}
注意:如果您使用的是Rust的较早版本,则可能需要删除dyn
关键字。在当前(2015)版本的Rust中,它是可选的。
答案 1 :(得分:3)
DK. has already explained why,但我想提供一种替代解决方法。
如Conditionally iterate over one of several possible iterators中所述,如果两个特征类型都相同,则可以创建一个实现特征的枚举。例如:
extern crate rand; // 0.6.5
use rand::{rngs::OsRng, thread_rng, RngCore};
fn rng() -> impl RngCore {
match OsRng::new() {
Ok(rng) => EitherRng::Left(rng),
Err(_) => EitherRng::Right(thread_rng()),
}
}
enum EitherRng<L, R> {
Left(L),
Right(R),
}
impl<L, R> RngCore for EitherRng<L, R>
where
L: RngCore,
R: RngCore,
{
fn next_u32(&mut self) -> u32 {
match self {
EitherRng::Left(l) => l.next_u32(),
EitherRng::Right(r) => r.next_u32(),
}
}
fn next_u64(&mut self) -> u64 {
match self {
EitherRng::Left(l) => l.next_u64(),
EitherRng::Right(r) => r.next_u64(),
}
}
fn fill_bytes(&mut self, b: &mut [u8]) {
match self {
EitherRng::Left(l) => l.fill_bytes(b),
EitherRng::Right(r) => r.fill_bytes(b),
}
}
fn try_fill_bytes(&mut self, b: &mut [u8]) -> Result<(), rand::Error> {
match self {
EitherRng::Left(l) => l.try_fill_bytes(b),
EitherRng::Right(r) => r.try_fill_bytes(b),
}
}
}
either crate为基本特征提供了许多这类实现。
另请参阅: