英文:
Literals in Trait methods implementing generics
问题
我正在尝试学习在Rust中使用Generics
和Traits
,并使用num
crate编写泛型代码。我得到了以下编译器错误:
6 | return self.gt(0)
| -- ^ 期望类型参数 `T`,但找到整数
在这个代码块上。
如果我使用num::zero
,它可以正常工作。但这会限制它只能使用num
crate中定义的符号。我希望它能在trait方法中与任何整数字面量一起工作。如何解决这个问题?
我尝试过0 as Integer
,但它不会编译,也尝试过0 as i32
等等。
英文:
I'm trying to learn Generics
and Traits
in Rust and using the num
crate to write generic code.
I get the following compiler error
6 | return self.gt(0)
| -- ^ expected type parameter `T`, found integer
on this code block.
use num::{Integer, zero};
trait CanCompareGreater<T: Integer> {
fn gt(&self, other: T) -> bool;
fn is_positive(&self) -> bool {
return self.gt(0)
}
}
struct MyNumber {
num: i32,
}
impl CanCompareGreater<i32> for MyNumber
{
fn gt(&self, other: i32) -> bool {
self.num > other
}
}
fn main() {
let n = MyNumber {num: 5};
println!("{}", n.is_positive());
}
If I use num::zero
it works correctly.
But that restricts it to symbols defined in the num
crate. I want it to work with any integer literal in the trait methods.
How would I go about doing it ?
I've tried 0 as Integer
which doesn't compile 0 as i32
etc
答案1
得分: 2
更新: drewtato的回答可能比我的更好,因为它提供了基于num::NumCast(我不熟悉的一个trait)的解决方案。但需要注意的是,对于超出范围的值,T::from()
会返回None
。我们不是在谈论MyNumber
的实例num
字段中的特定值,而是在谈论作为参数传递给T::from(...)
的值。
我会保留我的答案,因为它可能仍然有助于理解为什么OP的示例不起作用。
让我们首先看看这个例子(与泛型或num库无关):
fn abc(a: i32) {
println!("Called abc with {a}");
}
fn main() {
let b = 23 as i16;
abc(b);
}
编译器会生成以下错误:
error[E0308]: mismatched types
--> src/main.rs:7:9
|
7 | abc(b);
| --- ^ expected `i32`, found `i16`
在CanCompareGreater::is_positive()
中,您尝试调用方法gt
,并传递特定类型(如i32
)的特定值,而期望一个泛型T: Integer
。这不能编译,因为T
的类型可能与您尝试传递的特定值的类型不同,然后您会遇到类似上面示例的情况。
英文:
Update: drewtato's answer is probably better than mine, as it provides a solution based on num::NumCast (a trait I wasn't familiar with). A word of caution though: one needs to be aware that for out-of-range values T::from()
would return None
. We are not talking about the specific value in MyNumber
's instance num
field, but the value passed as a parameter to T::from(...)
.
I'll keep my answer below, as it might still be helpful in understanding why the OP's example didn't work.
Let's first take a look at this example (which has nothing to do with generics or the num crate:
fn abc(a: i32) {
println!("Called abc with {a}");
}
fn main() {
let b = 23 as i16;
abc(b);
}
The compiler emits the following error:
error[E0308]: mismatched types
--> src/main.rs:7:9
|
7 | abc(b);
| --- ^ expected `i32`, found `i16`
In CanCompareGreater::is_positive()
you are trying to call the method gt
by passing some specific value of a specific type (such as i32
) where a generic T: Integer
is expected. That cannot be compiled, because T
's type might happen to be different from the type of the specific value you are trying to pass, and then you'd get in a situation similar to the above example.
答案2
得分: 2
字面数字有自己的推断,与通用推断不同。这种推断不能逃离函数或依赖于泛型,所以你不能在这里使用它。你也不能使用 as
,因为它也与泛型推断无关。但有一个模仿 as
的 NumCast
特性。
use num::{Integer, NumCast};
trait CanCompareGreater<T: Integer + NumCast> {
fn gt(&self, other: T) -> bool;
fn is_positive(&self) -> bool {
return self.gt(T::from(4).unwrap())
}
}
还有一个 num_traits::AsPrimitive
,更接近 as
,因为它是不会失败的。
英文:
Literal numbers have their own inference going on that's separate from generic inference. This inference can't escape the function or depend on generics, so you can't use it here. You also can't use as
since that is also not connected to generic inference. But there's the NumCast
trait that mimics as
.
use num::{Integer, NumCast};
trait CanCompareGreater<T: Integer + NumCast> {
fn gt(&self, other: T) -> bool;
fn is_positive(&self) -> bool {
return self.gt(T::from(4).unwrap())
}
}
There's also num_traits::AsPrimitive
which is closer to as
since it is infallible.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论