我想知道这是正常还是错误:
struct A<T> (T);
impl<T> Add<A<T>, A<T>> for A<T>
where T: Add<T, T> + Deref<T> + Copy {
fn add(&self, &A(b): &A<T>) -> A<T> {
let A(a) = *self;
A(a.add(&b))
}
}
产生此错误:
<anon>:7:11: 7:12 error: reached the recursion limit while auto-dereferencing T [E0055]
<anon>:7 A(a.add(&b))
替换a.add(&b)
a+b
编译时没有错误
a+b
不是a.add(&b)
应该只是糖?
答案 0 :(得分:5)
短版本: T
实施Deref<T>
没有任何意义,因此方法调用和操作员调用在取消引用左侧方面的工作方式有所不同,因为a + b
不与a.add(&b)
完全相同。
长版:
+
运算符和Add.add
在获取引用方面的运作方式不同。
+
运算符通过引用本身获取两个操作数。对于各种类型a + b
和A
的操作数,B
要求对Add<B, C>
执行A
,并生成C
类型的值}。如上所述,a
和b
仅供参考;它默默地使这些引用本身;没有猜测。以下是它们的工作原理:
let a = 1i;
let b = a + a; // this one works
let c = a + &a; // mismatched types: expected `int`, found `&int` (expected int, found &-ptr)
let d = &a + a; // binary operation `+` cannot be applied to type `&int`
let e = &a + &a; // binary operation `+` cannot be applied to type `&int`
其中任何一个都没有解除引用,因此狡猾的T: Deref<T>
要求不会造成任何影响。
Add.add
通过引用获取这两个值。作为常规函数调用,它具有在必要时自动解除引用并引用左侧的能力。虽然右侧作为方法参数按原样传递,但是左侧会被解除引用,以找到add
可能意味着的所有可能方法。通常这很好,它会做你想要的,但在这种情况下它不会,因为T
(类型a
是)实现Deref<T>
。所以取消引用会得到T
。然后T
,实施Deref<T>
,取消引用T
。更重要的是,T
实现Deref<T>
,因此取消引用T
。它一直这样做,直到达到递归限制。实际上,T
实施Deref<T>
根本没有任何意义。
为了进行比较,以下是方法调用添加如何工作的一些演示:
let a = 1i;
let b = a.add(a); // mismatched types: expected `&int`, found `int` (expected &-ptr, found int)
let c = a.add(&a); // this one works (a reference to the LHS is taken automatically)
let d = (&a).add(a); // mismatched types: expected `&int`, found `int` (expected &-ptr, found int)
let e = (&a).add(&a); // this one works (LHS is dereferenced and then rereferenced)