文章来源于网络收集而来,版权归原创者所有,如有侵权请及时联系!
8.2 方法
依附于实例的称 方法 (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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论