我在Rust(版本1.0)中有关于泛型的新手问题。
假设我写了一个泛型函数来进行除法。别担心这种功能的用处;这个问题很简单,这是一个简单的功能。
fn divide<T: std::ops::Div>(a: T, b: T) -> T {
a / b
}
fn main() {
println!("{}", divide(42, 18))
}
该程序无法编译。
src/main.rs:2:5: 2:10 error: mismatched types:
expected `T`,
found `<T as core::ops::Div>::Output`
(expected type parameter,
found associated type) [E0308]
src/main.rs:2 a / b
^~~~~
我知道编译器错误告诉我,除法运算的结果是Output
,而不是T
,我在standard library documentation中看到了Output
类型}。
如何从Output
转换为T
?我尝试使用as
进行投射。
fn divide<T: std::ops::Div>(a: T, b: T) -> T {
(a / b) as T
}
fn main() {
println!("{}", divide(42, 18))
}
这会导致不同的编译器错误。
src/main.rs:2:5: 2:17 error: non-scalar cast: `<T as core::ops::Div>::Output` as `T`
src/main.rs:2 (a / b) as T
^~~~~~~~~~~~
我没有想法让这项工作成为现实,而且我意识到我对这里的语言基本缺乏了解,但我甚至不知道该怎么做才能使这项工作成功。帮助
答案 0 :(得分:11)
您只需指定T::Output
作为函数的返回类型:
fn divide<T: std::ops::Div>(a: T, b: T) -> T::Output {
a / b
}
修改以添加有关您无法在功能内进行强制转换的原因的更多说明
当你处于通用函数除法时,编译器还不知道你可以将T
转换为T::Output
,因此转换无效。它们是通用类型,它们可以是任何东西,编译器如何知道您可以从T
转换为T::Output
?
a / b
生成T::Output
类型的内容,因此在上面的解决方案中没有强制转换,T::Output
只是正确的类型。
编辑以使用std :: convert :: From
添加另一种可能的解决方案最常见的(我认为)通用实现是当你知道从T::Output
到T的转换是可能的时候。您可以约束T
为From
实施T::Output
。
这是一个完整的例子:
use std::ops::Div;
use std::convert::From;
fn divide<T: Div>(a: T, b: T) -> T
where T: From<<T as Div>::Output>
{
T::from(a / b)
}
#[derive(Debug)]
struct Bip(u32);
impl Div for Bip {
type Output = f32;
fn div(self, rhs: Bip) -> f32 {
(self.0 / rhs.0) as f32
}
}
impl From<f32> for Bip {
fn from(value: f32) -> Self {
Bip(value as u32)
}
}
fn main() {
println!("{:?}", divide(12, 4));
println!("{:?}", divide(Bip(12), Bip(4)));
}
答案 1 :(得分:6)
安德烈亚斯的回答解释了为什么演员阵容不可能,并且尽可能使这个功能变得通用解决了这个问题。
然而,这不是唯一的解决方案。 Rust还支持限制泛型函数的相关类型(此处为Output
)。
另一种选择是:
use std::ops::Div;
fn divide<T>(a: T, b: T) -> T
where T: Div<Output = T>
{
a / b
}
<Output = T>
位指示编译器仅接受T
的实现Div
等于Output
的函数类型T
。这显然更具限制性,但它可以确保divide
的结果属于T
类型。