了解 Vec<T> 的调试实现
Understanding the Debug implementation for Vec<T>
在尝试为自定义类型实现 Debug
特征时,我偶然发现了 Vec<T>
的实现。我很难理解它是如何工作的。
实现是这样的:
impl<T: fmt::Debug> fmt::Debug for Vec<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(&**self, f)
}
}
我知道它调用了一些其他类型的 fmt
实现。我无法理解的是它是什么类型。我试图在 , and searching among the implementations of Debug
的帮助下找到合适的东西(可能是 &[T]
),但没有成功。
在这种情况下 &**self
的确切含义是什么?正在调用 Debug
的哪个实现?
在这种情况下,我发现让编译器告诉您类型是什么很有用。只需导致类型错误,让编译器诊断程序为您完成。最简单的方法是尝试将您的项目分配给类型 ()
:
fn main() {
let v = &vec![1,2,3];
let () = v;
let () = &**v;
}
错误是:
<anon>:3:9: 3:11 error: mismatched types:
expected `&collections::vec::Vec<_>`,
found `()`
(expected &-ptr,
found ()) [E0308]
<anon>:3 let () = v;
^~
<anon>:4:9: 4:11 error: mismatched types:
expected `&[_]`,
found `()`
(expected &-ptr,
found ()) [E0308]
<anon>:4 let () = &**v;
^~
因此 v
是 &collections::vec::Vec<_>
而 &**v
是 &[_]
。
更详细,Vec
有这个:
impl<T> Deref for Vec<T> {
type Target = [T];
// ...
}
所以,我们解引用一次从 &Vec<T>
到 Vec<T>
,再解引用 得到 [T]
,然后引用一次获得 &[T]
.
[T]
有这个:
impl<T> Debug for [T] {
fn fmt(&self, ...) ...;
}
然而,当寻找一个合适的方法来调用时,Rust 会目标。这意味着我们可以从 &[T]
.
中找到 [T]
上的方法
由于,Debug::fmt
取&self
,所以直接用&[T]
调用就可以找到匹配的实现。无需任何自动引用或取消引用。
在尝试为自定义类型实现 Debug
特征时,我偶然发现了 Vec<T>
的实现。我很难理解它是如何工作的。
实现是这样的:
impl<T: fmt::Debug> fmt::Debug for Vec<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(&**self, f)
}
}
我知道它调用了一些其他类型的 fmt
实现。我无法理解的是它是什么类型。我试图在 Debug
的帮助下找到合适的东西(可能是 &[T]
),但没有成功。
在这种情况下 &**self
的确切含义是什么?正在调用 Debug
的哪个实现?
在这种情况下,我发现让编译器告诉您类型是什么很有用。只需导致类型错误,让编译器诊断程序为您完成。最简单的方法是尝试将您的项目分配给类型 ()
:
fn main() {
let v = &vec![1,2,3];
let () = v;
let () = &**v;
}
错误是:
<anon>:3:9: 3:11 error: mismatched types:
expected `&collections::vec::Vec<_>`,
found `()`
(expected &-ptr,
found ()) [E0308]
<anon>:3 let () = v;
^~
<anon>:4:9: 4:11 error: mismatched types:
expected `&[_]`,
found `()`
(expected &-ptr,
found ()) [E0308]
<anon>:4 let () = &**v;
^~
因此 v
是 &collections::vec::Vec<_>
而 &**v
是 &[_]
。
更详细,Vec
有这个:
impl<T> Deref for Vec<T> {
type Target = [T];
// ...
}
所以,我们解引用一次从 &Vec<T>
到 Vec<T>
,再解引用 得到 [T]
,然后引用一次获得 &[T]
.
[T]
有这个:
impl<T> Debug for [T] {
fn fmt(&self, ...) ...;
}
然而,当寻找一个合适的方法来调用时,Rust 会&[T]
.
[T]
上的方法
由于Debug::fmt
取&self
,所以直接用&[T]
调用就可以找到匹配的实现。无需任何自动引用或取消引用。