Rust中的方法
Cukor丘克 人气:0Rust中的方法
方法其实就是结构体的成员函数,在C语言中的结构体是没有成员函数的,但是Rust毕竟也是一门面向对象的编程语言,所以给结构体加上方法的特性很符合面向对象的特点。
方法的简单概念
方法(method)与函数类似:它们使用 fn
关键字和名称声明,可以拥有参数和返回值,同时包含在某处调用该方法时会执行的代码。不过方法与函数是不同的,因为它们在结构体的上下文中被定义,并且它们第一个参数总是 self
,它代表调用该方法的结构体实例。
&self
实际上是self: &Self
的缩写,在一个impl
块中,Self
类型是impl
块的类型的别名。方法的第一个参数必须有一个名为self
的Self
类型的参数,所以 Rust 让你在第一个参数位置上只用self
这个名字来缩写。传参的时候可以忽略self的传参。
上面这段话是官方文档对方法的描述。如果学过面向对象的应该理解起来是没人任何问题的,方法就是类中的成员函数,在调用方法是必须通过类的实例对象类调用。
使用方法代替函数的好处:
- 减少self参数的书写
- 组织性好
定义方法
定义方法的方式和定义函数的方式类似,也是采用fn作为标识,但是方法比函数多一点的就是需要被包含在impl中。
impl是implementation的简写,翻译成中文就是实施,实现的意思。在Rust中所有的方法都必须在对应的结构体的impl中实现,并且方法的第一个参数是&self,其中&self就是指向当前对象的引用,类似于C++中的this、Java中的this、Python中的self.
基本结构:
impl 结构体名 { 方法1... 方法2... .... 方法n... } //也可以再开一个impl impl 结构体名 { 方法n+1.... } //其中以上的效果和下面写法等效 impl 结构体名 { 方法1... 方法2... .... 方法n... 方法n+1.... }
可以重开一个impl的特性就像C++中的namespace一样,如果想了解namespace的可自行查询资料。
综上所述,impl的作用就是用来标识哪些方法是属于哪个结构体的。
例子:
struct MM { name: String, age: u8, } impl MM { fn get_name(&self) -> &str { &self.name } fn get_age(&self) -> &u8 { &self.age } } impl MM { fn show(&self) { println!("name: {}", self.name); println!("age: {}", self.age); } } /*上面两个impl等效于以下代码 impl MM { fn get_name(&self) -> &str { &self.name } fn get_age(&self) -> &u8 { &self.age } fn show(&self) { println!("name: {}", self.name); println!("age: {}", self.age); } } */ fn main() { let mm = MM { name: String::from("Alice"), age: 18, }; mm.show(); println!("{}的名字叫: {}, 她今年{}岁了", mm.name, mm.get_name(), mm.get_age()); }
结果:
name: Alice
age: 18
Alice的名字叫: Alice, 她今年18岁了
Rust自动引用和解引用
在C++中访问对象的内容,一般都是使用指针和指针运算符->
来访问对象中的属性(成员变量)和行为(成员函数)。但是在Rust没有和->
等效的运算符。Rust是存在了自动引用和解引用的功能。
当使用对象来调用方法时,Rust会自动为对象添加&
、&mut
或*
以便对象与方法签名匹配,即下面的代码是等价的:
mm.show(); //这种方法比较简洁 (&mm).show(); //这种方法稍微多了点东西
这种自动引用的行为之所以有效,是因为方法有一个明确的接收者———— self
的类型。在给出接收者和方法名的前提下,Rust 可以明确地计算出方法是仅仅读取(&self
),做出修改(&mut self
)或者是获取所有权(self
)。事实上,Rust 对方法接收者的隐式借用让所有权在实践中更友好。
//以下都是等效的,都可以修改age的值 mm.age = 19; (&mut mm).age = 89;
Rust 对方法接收者的隐式借用让所有权在实践中更友好。意思就是使用对象直接点操作就行了。
带参数的方法
因为方法和函数是类似的,所以在方法中也是可以传参的。
直接看一个例子就直接跳过了。
impl MM { //前面已经声明过MM的结构体了 fn eat(&self, food: &String) { println!("{}想吃{}", self.name, food); } } fn main() { let mm = MM { name: String::from("Alice"), age: 18, money: 100, }; mm.eat(&"手撕鸡".to_string()); }
结果:
Alice想吃手撕鸡
小结
结构体有意义的自定义类型。通过结构体,我们可以将相关联的数据片段联系起来并命名它们,这样可以使得代码更加清晰。在 impl
块中,你可以定义与你的类型相关联的函数,而方法是一种相关联的函数,让你指定结构体的实例所具有的行为。
但结构体并不是创建自定义类型的唯一方法:让我们转向 Rust 的枚举功能,为你的工具箱再添一个工具。
加载全部内容