我使用From
特征将i32
转换为我自己的结构。我在一个不编译的泛型函数do_stuff
中使用此转换:
use std::convert::*;
struct StoredValue {
val: i32,
}
impl From<i32> for StoredValue {
fn from(value: i32) -> StoredValue {
return StoredValue {val: value};
}
}
/// Generic function that stores a value and do stuff
fn do_stuff<T>(value: T) -> i32 where T: From<T> {
let result = StoredValue::from(value);
// .... do stuff and
return 0;
}
fn main () {
let result = do_stuff(0); // call with explicit type
}
和编译错误:
main.rs:15:18: 15:35 error: the trait `core::convert::From<T>` is not implemented for the type `StoredValue` [E0277]
main.rs:15 let result = StoredValue::from(value);
为From<T>
实现StoredValue
的通用版本是否有意义?
答案 0 :(得分:2)
你的泛型函数说,“我接受任何实现自己创建的类型。”这不是你想要的。
你可以想要说些什么:
“我接受任何可以转换为i32
的类型,以便我可以创建StoredValue
。”这是有效的,因为您知道StoredValue
实现了From<i32>
。
fn do_stuff<T>(value: T) -> i32 where T: Into<i32> {
let result = StoredValue::from(value.into());
// ...
}
或者,“我接受任何可以将转换为 a StoredValue
的类型。”有一个方便的特征与From<T>
特征一起,它被称为Into<T>
。
fn do_stuff<T>(value: T) -> i32 where T: Into<StoredValue> {
let result = value.into();
// ...
}
记住如何/何时使用这两个特征的方法是:
Into<T>
,即来自?->T
From<T>
,而不是最终结果,即T->?
这两个特征可以齐头并进的原因是,如果你有一个T
来实现Into<U>
,你有V
来实现From<U>
你可以来自T->U->V
。
Rust std lib已经进行了这样的转换,其中说“实现T
的任何类型From<U>
,而不是U
实现Into<T>
。”
因此,当您实施From<i32> for StoredValue
时,您可以假设有Into<StoredValue> for i32
。
答案 1 :(得分:1)
要使do_stuff()
有效,必须可以将T
类型转换为StoredValue
。所以它的声明应该是
fn do_stuff<T>(value: T) -> i32 where StoredValue: From<T> {
编辑:我同意Shepmaster认为最好
fn do_stuff<T>(value: T) -> i32 where T: Into<StoredValue> {
let result = value.into();
// ...
由于存在将T: From<U>
转换为U: Into<T>
的通用实现,因此允许使用两种类型的转换,即实现From
的转换和实现Into
的转换。在我的第一个版本中,只有实现From
的转化才有效。