编者注:此代码示例来自1.0之前的Rust版本,并且在语法上不是有效的Rust 1.0代码.此代码的更新版本会产生不同的错误,但答案仍包含有价值的信息.
在下列情况下,似乎我们无法测试相等性.为什么是这样?有解决方法吗?(我正在使用Rust 0.11).
trait A: PartialEq {}
#[deriving(PartialEq)]
enum T {Ta, Tb}
impl A for T {}
fn main() {
assert!(Ta == Ta);
assert!(Ta != Tb);
assert!(some_fn(&Ta, &Ta));
assert!(!some_fn(&Ta, &Tb));
}
fn some_fn(an_a: &A, another_a: &A) -> bool {
an_a == another_a
// ERROR ^~~~~~~~~~~~ binary operation `==` cannot be applied to type `&A`
}
fn another_fn(an_a: &A + PartialEq, another_a: &A + PartialEq) -> bool {
// ERROR: ^~~~~~~~~ only the builtin traits can be used as closure or object bounds
an_a == another_a
}
Run Code Online (Sandbox Code Playgroud)
Vla*_*eev 11
以下是特征的定义PartialEq:
pub trait PartialEq<Rhs = Self>
where
Rhs: ?Sized,
{
fn eq(&self, other: &Rhs) -> bool;
fn ne(&self, other: &Rhs) -> bool { ... }
}
Run Code Online (Sandbox Code Playgroud)
请注意Self参数类型.这意味着eq()和ne()方法接受与实现者相同类型的参数.例如:
impl PartialEq for i32 {
fn eq(&self, other: &i32) -> bool { ... }
}
impl PartialEq for String {
fn eq(&self, other: &String) -> bool { ... }
}
Run Code Online (Sandbox Code Playgroud)
请注意如何实现other反映类型的更改类型PartialEq.
这就是问题.在特征对象中,实际类型在运行时被擦除且不可用.这意味着不可能从特征对象获得对具体类型的引用; 特别是,你不能去&A到&T在你的榜样.
这意味着无法调用接受或返回Self特征对象类型的方法.实际上,这些方法总是需要一个具体的类型,但如果你只有一个特征对象,就没有具体的类型,并且这种方法无法以任何合理的方式工作.
She*_*ter 10
在 trait 对象的某些情况下,您希望基于通过 trait 公开的一些属性来比较它们。您可以通过在 trait 类型本身上实现方法来实现这一点:
trait A {
fn id(&self) -> i32;
}
impl PartialEq for dyn A + '_ {
fn eq(&self, other: &Self) -> bool {
self.id() == other.id()
}
}
impl Eq for dyn A + '_ {}
fn some_fn(an_a: &dyn A, another_a: &dyn A) -> bool {
an_a == another_a
}
Run Code Online (Sandbox Code Playgroud)
这并没有直接解决想要委托回PartialEq底层类型的实现的原始情况,但是您可以结合现有的解决方案:
impl PartialEq for dyn A + '_ {
fn eq(&self, other: &Self) -> bool {
self.equals_a(other)
}
}
Run Code Online (Sandbox Code Playgroud)
也可以看看:
在弗拉基米尔·马特维耶夫(Vladimir Matveev)的帮助下,我想出了如何使用Any将我的特质转向具体类型并测试结果值是否相等:
// `Any` allows us to do dynamic typecasting.
use std::any::Any;
trait A {
// An &Any can be cast to a reference to a concrete type.
fn as_any(&self) -> &dyn Any;
// Perform the test.
fn equals_a(&self, _: &dyn A) -> bool;
}
#[derive(Debug, PartialEq)]
enum T {
Ta,
Tb,
}
// Implement A for all 'static types implementing PartialEq.
impl<S: 'static + PartialEq> A for S {
fn as_any(&self) -> &dyn Any {
self
}
fn equals_a(&self, other: &dyn A) -> bool {
// Do a type-safe casting. If the types are different,
// return false, otherwise test the values for equality.
other
.as_any()
.downcast_ref::<S>()
.map_or(false, |a| self == a)
}
}
fn main() {
assert_eq!(T::Ta, T::Ta);
assert_ne!(T::Ta, T::Tb);
assert!(some_fn(&T::Ta, &T::Ta));
assert!(!some_fn(&T::Ta, &T::Tb));
}
fn some_fn(an_a: &dyn A, another_a: &dyn A) -> bool {
// It works!
an_a.equals_a(another_a)
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3033 次 |
| 最近记录: |