2.7 Rust Structs
A struct, or structure, is a custom data type that lets you name and package together multiple related values that make up a meaningful group.
Defining and Instantiating Structs
相比元组,struct中的属性是无序的
To define a struct, we enter the keyword struct
and name the entire struct. A struct’s name should describe the significance of the pieces of data being grouped together. Then, inside curly brackets, we define the names and types of the pieces of data, which we call fields.
struct User {
username: String,
email: String,
sign_in_count: u64,
active: bool,
}
let user1 = User {
email: String::from("someone@example.com"),
username: String::from("someusername123"),
active: true,
sign_in_count: 1,
};
如果其属性可能被修改,那么其实例必须声明为mut可变类型
let mut user1 = User {
email: String::from("someone@example.com"),
username: String::from("someusername123"),
active: true,
sign_in_count: 1,
}; user1.email = String::from("anotheremail@example.com");
Note that the entire instance must be mutable; Rust doesn’t allow us to mark only certain fields as mutable. As with any expression, we can construct a new instance of the struct as the last expression in the function body to implicitly return that new instance.
fn build_user(email: String, username: String) -> User {
User {
email: email,
username: username,
active: true,
sign_in_count: 1,
}
}
we can use the field init shorthand syntax to rewrite build_user
so that it behaves exactly the same but doesn’t have the repetition of email
and username
fn build_user(email: String, username: String) -> User {
User {
email,
username,
active: true,
sign_in_count: 1,
}
}
Creating Instances From Other Instances With Struct Update Syntax
It’s often useful to create a new instance of a struct that uses most of an old instance’s values but changes some. You’ll do this using struct update syntax.
let user2 = User {
email: String::from("another@example.com"),
username: String::from("anotherusername567"),
active: user1.active,
sign_in_count: user1.sign_in_count,
};
The syntax ..
specifies that the remaining fields not explicitly set should have the same value as the fields in the given instance.
let user2 = User {
email: String::from("another@example.com"),
username: String::from("anotherusername567"),
..user1
};
完整示例
fn main() {
println!("Hello, struct!");
update_user();
let user2: User = build_user("it@163.com".to_string(),"mysql".to_string());
print_user(&user2); let user3: User = User{
username: "dbcheck@163.com".to_string(),
email: "dbcheck@163.com".to_string(),
..user2
};
print_user(&user3);
} struct User{
username: String,
email: String,
userid: u64,
active: bool,
} fn print_user(user1: &User){ println!("{},{},{},{}",user1.username,user1.email,user1.userid,user1.active);
} fn update_user(){
let mut user1 = User{
username: String::from("用户名"),
email: String::from("itoracle@aliyun.com"),
userid: 1,
active: true,
};
user1.active = false; print_user(&user1)
} fn build_user(email: String, username: String) -> User {
User {
email,
username,
active: true,
userid: 1,
}
}
运行结果
Finished dev [unoptimized + debuginfo] target(s) in 0.01s
Running `target/debug/b_struct`
Hello, struct!
用户名,itoracle@aliyun.com,1,false
mysql,it@163.com,1,true
dbcheck@163.com,dbcheck@163.com,1,true
Using Tuple Structs without Named Fields to Create Different Types
元组结构体,无字段名称,有元组的特性
fn test_tu(){
let _tup: (i32, f64, u8) = (500, 6.4, 1);
let _aa = (1,2.3,"wa ka ka ");
let (_x,_y,_z) = _aa;
println!("The value of z is:{}",_z); struct Color(i32, i32, i32);
struct Point(i32, i32, i32); let black = Color(0, 0, 0);
let origin = Point(0, 0, 0);
println!("color:{},{},{}",black.0,black.1,black.2);
println!("origin:{},{},{}",origin.0,origin.1,origin.2);
}
输出
The value of z is:wa ka ka
color:0,0,0
origin:0,0,0
ownership,引用只能作用于struct对象,不能作用于其属性
struct Rectangle {
width: u32,
height: u32,
} fn main() {
let rect1 = Rectangle { width: 30, height: 50 }; println!(
"The area of the rectangle is {} square pixels.",
area(&rect1)
);
} fn area(rectangle: &Rectangle) -> u32 {
rectangle.width * rectangle.height
}
输出整个struct
fn main() {
println!("Hello, struct!");
test_user();
} #[derive(Debug)]
struct User{
username: String,
email: String,
userid: u64,
active: bool,
} fn test_user(){
let u1 = User{
username: "败者千千万,胜者唯一人".to_string(),
email: "itoracle@163.com".to_string(),
userid: 123,
active: false,
};
println!("user:{:?}",u1);
}
输出
Hello, sturct!
user:User { username: "败者千千万,胜者唯一人", email: "itoracle@163.com", userid: 123, active: false }
fn main() {
println!("Hello, struct!");
test_user();
} #[derive(Debug)]
struct User{
username: String, email: String,
userid: u64,
active: bool,
} fn test_user(){
let u1 = User{
username: "败者千千万,胜者唯一人".to_string(),
email: "itoracle@163.com".to_string(),
userid: 123,
active: false,
};
println!("user:{:#?}",u1);
}
输出
Hello, struct!
user:User {
username: "败者千千万,胜者唯一人",
email: "itoracle@163.com",
userid: 123,
active: false,
}
结构体方法
分两类:Methods、Associated Functions
Methods:实例相关,第一个参数必须为&self或&mut self,调用方式为 实例.方法名
Associated Functions:struct相关,无须传入self参数,跟实例没关系,是关联在struct上的,相当基于Java语言中的静态方法,调用方式为 struct名称::方法名
Methods
#[derive(Debug)]
struct Rectangle {
width: u32,
height: u32,
} impl Rectangle { //impl -> implementation
fn area(&self) -> u32 { //self -> rectangle: &Rectangle
self.width * self.height
}
} fn main() {
let rect1 = Rectangle { width: 30, height: 50 }; println!(
"The area of the rectangle is {} square pixels.",
rect1.area()
);
}
In the signature for area
, we use &self
instead of rectangle: &Rectangle
because Rust knows the type of self
is Rectangle
due to this method’s being inside the impl Rectangle
context. Note that we still need to use the &
before self
, just as we did in &Rectangle
. Methods can take ownership of self
, borrow self
immutably as we’ve done here, or borrow self
mutably, just as they can any other parameter.
We’ve chosen &self
here for the same reason we used &Rectangle
in the function version: we don’t want to take ownership, and we just want to read the data in the struct, not write to it. If we wanted to change the instance that we’ve called the method on as part of what the method does, we’d use &mut self
as the first parameter. Having a method that takes ownership of the instance by using just self
as the first parameter is rare; this technique is usually used when the method transforms self
into something else and you want to prevent the caller from using the original instance after the transformation.
Rust自动处理了对象对其方法或属性的调用
上面的例子中,方法传入的参数&self是引用类型,但其调用属性的时候使用的是self.width,其等价于(&self).width
In C and C++, two different operators are used for calling methods: you use . if you’re calling a method on the object directly and -> if you’re calling the method on a pointer to the object and need to dereference the pointer first. In other words, if object is a pointer, object->something() is similar to (*object).something(). Rust doesn’t have an equivalent to the -> operator; instead, Rust has a feature called automatic referencing and dereferencing. Calling methods is one of the few places in Rust that has this behavior. Here’s how it works: when you call a method with object.something(), Rust automatically adds in &, &mut, or * so object matches the signature of the method. In other words, the following are the same: p1.distance(&p2);
(&p1).distance(&p2);
The first one looks much cleaner. This automatic referencing behavior works because methods have a clear receiver—the type of self. Given the receiver and name of a method, Rust can figure out definitively whether the method is reading (&self), mutating (&mut self), or consuming (self). The fact that Rust makes borrowing implicit for method receivers is a big part of making ownership ergonomic in practice.
#[derive(Debug)]
struct Rectangle {
width: u32,
height: u32,
} impl Rectangle { //impl -> implementation
fn area(&self) -> u32 { //self -> rectangle: &Rectangle
(&self).width * self.height
} fn can_hold(&self, other: &Rectangle) -> bool {
self.width > other.width && self.height > other.height
}
} fn main() {
let rect1 = Rectangle { width: 30, height: 50 }; println!(
"The area of the rectangle is {} square pixels.",
rect1.area()
); let rect2 = Rectangle { width: 10, height: 40 };
let rect3 = Rectangle { width: 60, height: 45 }; println!("Can rect1 hold rect2? {}", rect1.can_hold(&rect2));
println!("Can rect1 hold rect3? {}", rect1.can_hold(&rect3)); }
输出
The area of the rectangle is 1500 square pixels.
Can rect1 hold rect2? true
Can rect1 hold rect3? false
Associated Functions
Another useful feature of impl
blocks is that we’re allowed to define functions within impl
blocks that don’t take self
as a parameter. These are called associated functions because they’re associated with the struct. They’re still functions, not methods, because they don’t have an instance of the struct to work with. You’ve already used the String::from
associated function.
impl Rectangle {
fn square(size: u32) -> Rectangle {
Rectangle {
width: size,
height: size,
}
}
}
To call this associated function, we use the ::
syntax with the struct name; let sq = Rectangle::square(3);
is an example. This function is namespaced by the struct: the ::
syntax is used for both associated functions and namespaces created by modules.
struct方法的首个参数必须是&self,或者self
&self以引用的方式使用,不涉及ownership
self 会生发ownership转移,调用一次后,不能再使用该对象
推荐使用&self
#[derive(Debug)]
struct Rectangle {
width: u32,
height: u32,
} impl Rectangle {
fn area(&self) -> u32 {
self.width * self.height
} fn init(&mut self, w: u32,h: u32) {
self.width = w;
self.height = h;
} } pub fn test1() {
let mut r1 = Rectangle {width:10, height:30};
println!(
"area:{}",
r1.area()
); r1.init(10,20);
println!(
"area:{}",
r1.area()
); }
2.7 Rust Structs的更多相关文章
- 转 A Week with Mozilla's Rust
转自http://relistan.com/a-week-with-mozilla-rust/ A Week with Mozilla's Rust I want another systems la ...
- Rust 中的继承与代码复用
在学习Rust过程中突然想到怎么实现继承,特别是用于代码复用的继承,于是在网上查了查,发现不是那么简单的. C++的继承 首先看看c++中是如何做的. 例如要做一个场景结点的Node类和一个Sprit ...
- Rust入坑指南:千人千构
坑越来越深了,在坑里的同学让我看到你们的双手! 前面我们聊过了Rust最基本的几种数据类型.不知道你还记不记得,如果不记得可以先复习一下.上一个坑挖好以后,有同学私信我说坑太深了,下来的时候差点崴了脚 ...
- Rust 基础学习
所有权: 变量具有唯一所有权.如果一个类型拥有 Copy trait,一个旧的变量在将其赋值给其他变量后仍然可用.除此之外,赋值意味着转移所有权.Rust 不允许自身或其任何部分实现了 Drop tr ...
- [易学易懂系列|rustlang语言|零基础|快速入门|(11)|Structs结构体]
[易学易懂系列|rustlang语言|零基础|快速入门|(11)] 有意思的基础知识 Structs 我们今天来看看数据结构:structs. 简单来说,structs,就是用来封装相关数据的一种数据 ...
- rust实战系列 - 使用Iterator 迭代器实现斐波那契数列(Fibonacci )
为什么是斐波那契数列 斐波那契数列十分适合用来实战rust的迭代器,算法也很简单,一目了然.这个例子可以用来学习Iterator的使用,十分适合刚学习了rust的迭代器章节后用来练练手. 代码实战 d ...
- Rust 中的数据布局-repr
repr(Rust) 首先,所有类型都有一个以字节为单位的对齐方式,一个类型的对齐方式指定了哪些地址可以用来存储该值.一个具有对齐方式n的值只能存储在n的倍数的地址上.所以对齐方式 2 意味着你必须存 ...
- Rust语言的多线程编程
我写这篇短文的时候,正值Rust1.0发布不久,严格来说这是一门兼具C语言的执行效率和Java的开发效率的强大语言,它的所有权机制竟然让你无法写出线程不安全的代码,它是一门可以用来写操作系统的系统级语 ...
- Rust初步(七):格式化
在Rust中,如果要进行屏幕输出,或者写入到文件中,需要对数据进行格式化.这一篇总结一下它所支持的几种格式化方式. 这篇文章参考了以下官方文档,不过,按照我的风格,我还是会突出于C#语言的比较,这样可 ...
随机推荐
- MapReduce Service更换集群外部时钟源,仅需10步
摘要:MapReduce Service 集群使用NTP进行时钟同步.本文简要介绍了MapReduce Service集群NTP机制及NTP的配置方式. 本文分享自华为云社区<MapReduce ...
- python连接集群mongodb,封装增删改查
1.下载pymongo pip install pymongo 2.直接上代码 [ini配置文件] 封装读ini省略~~ [db.py] class Database(): def __init__( ...
- FZU ICPC 2020 寒假训练 6 —— 字符串处理
P1603 斯诺登的密码 题目描述 2013年X月X日,俄罗斯办理了斯诺登的护照,于是他混迹于一架开往委内瑞拉的飞机.但是,这件事情太不周密了,因为FBI的间谍早已获悉他的具体位置--但这不是最重要的 ...
- Highcharts › 自由绘图
... <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title ...
- 【linux系统】命令学习(四)统计命令
sort 排序 -b 忽略开头的空白符 -f 将小写字母看做为大写字母 -h 根据存储容量排序(kb mb hb )从小到大 -n 按数字排序 -o 把结果写入文件 -r 以相反的顺序来排序 -t 指 ...
- Vue: 一个简单的Vue2.0 v-model双向数据绑定的实现,含源代码,小白也能看懂
首先说一下原理吧 View层(dom元素)的变动如何响应到Model层(Js变量)呢? 通过监听元素的input事件来动态的改变js变量的值,实际上不是改变的js变量的值,而是改变的js变量的gett ...
- python中使用正则表达式处理文本(仅记录常用方法和参数)
标准库模块 python中通过re模块使用正则表达式 import re 常用方法 生成正则表达式对象 compile(pattern[,flags]) pattern:正则表达式字符串 flags: ...
- 访问ajax请求后的结果
let getJPM = (function() { let result; let url ="xxx"; $.ajax({ type: "post", ur ...
- Python迭代器生成器与生成式
Python迭代器生成器与生成式 什么是迭代 迭代是重复反馈过程的活动,其目的通常是为了逼近所需目标或结果.每一次对过程的重复称为一次"迭代",而每一次迭代得到的结果会作为下一次迭 ...
- Python+selenium定位一组元素,复选框