返回介绍

8.2 方法

发布于 2024-10-13 11:25:30 字数 4159 浏览 0 评论 0 收藏 0

依附于实例的称 方法 (method),而依附类型的是 关联函数 (associated function)。在其他语言里,我们习惯称之为实例方法和静态方法。

实例方法:

  • &self : 实例不可变引用。
  • &mut self : 实例可变引用。
  • self : 复制或转移所有权。
  • instance.method()

实例方法 self 参数名有特定含义,不能更换。可用同名方法作为字段 getter 。为便于阅读区分,本文暂不遵循该惯例。

关联函数:

  • 隐式参数 Self ,代表当前类型。(可在实例方法内使用)
  • self 参数,没有关联实例。
  • type::function()

impl 块为特定类型实现方法,可拆分成多个块进行功能分组。

不能为当前 crate 外的类型实现方法。

#[derive(Debug)]
struct Data { 
  x: i64 
}

impl Data {
  fn new(x: i64) -> Self    { Self { x: x } }
  fn test() { println!("{:?}", Self::new(1)); }

  fn get_x(&self) -> i64    { self.x }
  fn set_x(&mut self, x: i64) { self.x = x; }
  fn to_int(self) -> i64    { self.x }
}

/* ----------------------------------------------------- */

fn main() {
  let mut d = Data::new(10);
  assert_eq!(d.get_x(), 10);

  d.set_x(20);
  assert_eq!(d.get_x(), 20);

  
  // let x = d.to_int();
  //     -------- `d` moved due to this method call
  // println!("{:?}", d);
  //          ^ value borrowed here after move
}

在符合规则前提下,自动引用和解引用(auto referencing and dereferencing),转换成合适的 self 参数类型。当然,对于转移所有权的方法,不能以引用方式调用。除非实现 Copy 特征,变为接收副本。

fn main() {
  let mut d = Data::new(10);

  let r = &mut d;
  assert_eq!(r.get_x(), 10);

  r.set_x(20);
  assert_eq!(r.get_x(), 20);
  
  // r.to_int();
  // ^ cannot move out of `*r` which is behind a mutable reference
}
#[derive(Debug, Clone, Copy)]
struct Data {
  x: i64
}

fn main() {
  let d = Data::new(10);
  let r = &d;

  assert_eq!(r.to_int(), 10);  // copy
  assert_eq!(r.get_x(), 10);
}

链式调用

方法返回 self ,实现链式调用(chaining methods call)。

#[derive(Debug)]
struct Data {
  x: i32,
  y: i32,
}

/* ----------------------------------------------------- */

struct DataBuilder {
  data: Data
}

impl DataBuilder {
  fn new() -> DataBuilder {
    Self{ data: Data{x: 0, y: 0} }
  }

  fn x(&mut self, val: i32) -> &mut DataBuilder {
    self.data.x = val;
    self
  }

  fn y(&mut self, val: i32) -> &mut DataBuilder {
    self.data.y = val;
    self
  }

  fn finalize(&self) -> Data {
    Data{ ..self.data }
  }  
}

/* ----------------------------------------------------- */

fn main() {
  let d = DataBuilder::new()
        .x(1)
        .y(2)
        .finalize();

  assert_eq!(d.x, 1);
  assert_eq!(d.y, 2);
}

泛型方法

为泛型类型定义,也可为某具体类型定义。

如果说泛型是通用模板,那么再为其配上一套通用方法,可以让模板更全面,有数据,有行为。所有以该模板实例化的类型,都会 “继承” 这些方法。

鉴于通用模板方法和具体类型方法会 合并 ,所以不能有名称相同的定义,不支持重载。

下例中, impl<T>T 指明 Data<T>T 是个泛型参数。否则 Data<T> 被当作类似 Data<i32> 这样的具体类型,引发 cannot find type `T` in this scope 错误。

泛型方法调用时, <T> 尖括号可能被解析成比较操作符,建议写成 ::<T>

use std::default::Default;

#[derive(Debug)]
struct Data<T> {
  x: T
}

impl<T> Data<T> where 
  T: Copy + Default
{
  fn new() -> Data<T> { Self{ x: Default::default() } }

  fn get_x(&self) -> T    { self.x }
  fn set_x(&mut self, x: T) { self.x = x; }
}

/* ----------------------------------------------------- */

// 为 f32 实现方法,其他类型无法使用。
impl Data<f32> {
  fn print(&self) { println!("{:?}", self.x); }
}

/* ----------------------------------------------------- */

fn main() {
  let mut d = Data::<i32>::new();
  d.set_x(20);
  assert_eq!(d.get_x(), 20);

  // d.print();
  //   ^^^^^ method not found in `Data<{i32}>`

  let mut f = Data::<f32>::new();
  f.set_x(2.0);
  f.print();
  assert_eq!(f.get_x(), 2.0);
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文