我在文档中没找到 Self
,只在源代码中看到了它。而文档中只使用 self
。
我在文档中没找到 Self
,只在源代码中看到了它。而文档中只使用 self
。
Self
是当前对象的类型。它可能会出现在 trait
或者 impl
中,但通常出现在 trait
中,在这里它是一个替身,表示最终将要实现该 trait
的任何类型(在定义 trait
时未知):
trait Clone {
fn clone(&self) -> Self;
}
如果我实现Clone
:
impl Clone for MyType {
// I can use either the concrete type (known here)
fn clone(&self) -> MyType;
// Or I can use Self again, it's shorter after all!
fn clone(&self) -> Self;
}
如果我懒的话,我也可以在常规的impl
中使用它(它更短!):
impl MySuperLongType {
fn new(a: u32) -> Self { ... }
}
self
是在trait
或impl
中用于方法的第一个参数的名称。使用其他名称也是可能的,但有一个显著的区别:
self
,则引入的函数是一个方法在Rust中,没有隐式的this
参数传递给类型的方法:您必须显式地将“当前对象”作为方法参数传递。这将导致:
impl MyType {
fn doit(this: &MyType, a: u32) { ... }
}
正如我们所看到的,作为一种更短的形式,这也可以是(仍然啰嗦):
impl MyType {
fn doit(this: &Self, a: u32) { ... }
}
实际上这就是在底层发生的&self
的本质。
impl MyType {
fn doit(&self, a: u32) { ... }
}
因此,对应表如下:
self => self: Self
&self => self: &Self
&mut self => self: &mut Self
但是,调用这些函数的方式发生了变化:
impl MyType {
fn doit(&self, a: u32) {
// ...
}
fn another(this: &Self, a: u32) {
// ...
}
}
fn main() {
let m = MyType;
// Both can be used as an associated function
MyType::doit(&m, 1);
MyType::another(&m, 2);
// But only `doit` can be used in method position
m.doit(3); // OK: `m` is automatically borrowed
m.another(4); // ERROR: no method named `another`
}
self
与否不仅仅是语法问题,因为这是方法和关联函数之间的区别。对于一个简单的struct
,调用方法或关联函数在语法上大体相同(虽然糖并不那么糟糕)。然而,在特性上情况就有所改变:具体来说,Trait对象(例如与fn doit(d: &Display)
一起使用)只能在对象安全的特性上形成,而关联函数不是对象安全的(方法的子集也不安全)。 - Matthieu M.当self
被用作第一个方法参数时,它是self: Self
的简写。还有&self
,相当于self: &Self
,以及&mut self
,相当于self: &mut Self
。
在方法参数中使用的Self
是接收方法的类型(即该方法所在的impl
)的一种语法糖。这也允许使用不需要太多重复的泛型类型。
Self
指的是实现trait的当前类型,而self
则指代实例。
在Rust中,将self
作为第一个参数定义方法。这只是一种惯例,将函数转换为方法,类似于Python。从功能上讲,self
类似于JavaScript中的this
。
对于那些不知道函数和方法区别的人来说,方法是附加到实例并通过该实例调用的函数。
Self
是一个通用类型,这就是为什么它不允许出现在需要具体类型的任何位置的原因。这在Rust文档中通常被称为对象安全。
Self
还在impl
块内的方法定义中使用,以便在重构期间重命名类型时,您不必逐个修复每个方法。
在Rust中,self
还用于模块解析,它指的是当前模块。在此示例中,它导入io
模块:
use std::io::{self, Read};