Appearance
5.2 静态方法
没有 receiver 参数的方法(即第一个参数不是self
参数的方法)称作“静态方法”。静态方法可以通过Type::FunctionName()
的方式调用。需要注意的是,即便我们的第一个参数是Self
相关类型,只要变量名字不是self
,就不能使用小数点的语法调用函数。
rust
struct T(i32);
impl T {
// 这是一个静态方法
fn func(this: &Self) {
println!{"value {}", this.0};
}
}
fn main() {
let x = T(42);
// x.func(); 小数点方式调用是不合法的
T::func(&x);
}
在标准库中就有一些这样的例子。Box 的一系列方法Box::into_raw(b: Self)
Box::leak(b: Self)
,以及 Rc 的一系列方法Rc::try_unwrap(this: Self)
Rc::downgrade(this: &Self)
,都是这种情况。它们的 receiver 不是self
关键字,这样设计的目的是强制用户用Rc::downgrade(&obj)
的形式调用,而禁止obj.downgrade()
形式的调用。这样源码表达出来的意思更清晰,不会因为Rc<T>
里面的成员方法和T
里面的成员方法重名而造成误解问题(这又涉及 Deref trait 的内容,读者可以把第 16 章读完再回看这一段)。
trait 中也可以定义静态函数。下面以标准库中的std::default::Default
trait 为例,介绍静态函数的相关用法:
rust
pub trait Default {
fn default() -> Self;
}
上面这个 trait 中包含了一个default()
函数,它是一个无参数的函数,返回的类型是实现该 trait 的具体类型。Rust 中没有“构造函数”的概念。Default
trait 实际上可以看作一个针对无参数构造函数的统一抽象。
比如在标准库中,Vec::default()
就是一个普通的静态函数。
rust
// 这里用到了“泛型”,请参阅第 21 章
impl<T> Default for Vec<T> {
fn default() -> Vec<T> {
Vec::new()
}
}
跟 C++ 相比,在 Rust 中,定义静态函数没必要使用static
关键字,因为它把self
参数显式在参数列表中列出来了。作为对比,C++ 里面成员方法默认可以访问this
指针,因此它需要用static
关键字来标记静态方法。Rust 不采取这个设计,主要原因是self
参数的类型变化太多,不同写法语义差别很大,选择显式声明self
参数更方便指定它的类型。