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#语言的比较,这样可 ...
随机推荐
- lua入门之环境搭建、第一个demo
前言 前段时间因为有些项目功能需要,自己研究了下lua,今天整理下,并以一个demo为示例演示 手机上的运行效果 分为几个步骤来逐步讲解. 1.lua介绍,为什么选择它? 2.环境安装 3.撸一个简单 ...
- 🏆【Alibaba中间件技术系列】「RocketMQ技术专题」帮你梳理RocketMQ或Kafka的选择理由以及二者PK
前提背景 大家都知道,市面上有许多开源的MQ,例如,RocketMQ.Kafka.RabbitMQ等等,现在Pulsar也开始发光,今天我们谈谈笔者最常用的RocketMQ和Kafka,想必大家早就知 ...
- 使用 docker + verdaccio 搭建npm私有仓库
本文介绍如何使用 verdaccio 搭建私有npm仓库,以及使用 docker 时如何映射到本地目录,方便简单对仓库进行各种操作.系统环境是 Linux. verdaccio verdaccio 是 ...
- [ARC117D]Miracle Tree
将$E_{i}$从小到大排序(显然不会相同),假设$E_{p_{i}}$为从小到大第$i$小 此时,必然有$E_{p_{1}}=1$,否则可以将$E_{p_{i}}$都减去$E_{p_{1}}-1$, ...
- [loj2091]小星星
(分别用$E_{T}$和$E_{G}$表示树和图的边集) 简单分析,可以发现题目即求排列$p_{i}$的数量,满足$\forall (x,y)\in E_{T},(p_{x},p_{y})\in E_ ...
- [loj3179]视觉程序
暴力做法:1.对每一行/列求$or$:2.枚举行的差值$i$,并对任意相差为$i$的行和相差为$k-i$的列求$and$,对行/列的$and$结果求$or$,对行和列的$or$求$and$,对所有$i ...
- 【Tool】IntelliJ 搭建Node.js环境
IntelliJ IDEA 开发 Node.js 2019-07-29 14:12:34 by冲冲 1. 配置插件 在IDEA的 file -> setting -> Plugins, ...
- idea插件 Background Image Plus 随机更换背景图片
首先在市场搜索: Background Image Plus 设置图片: 在view中,有set 图片,有random图片,有clean图片的 设置就是用set,随便设置个路径. 重点来了,随机更换背 ...
- 藏书馆App基于Rainbond实现云原生DevOps的实践
我们需要的不是精通Kubernetes的工程师,我们需要一款小白都能用好的管理工具. -- 厦门正观易知科技有限公司运维负责人 郭传壕 大家好,我是厦门正观易知科技有限公司运维负责人郭传壕. 藏书馆是 ...
- expr计算字符串长度
命令:expr length "quanzhiqinag" #!/bin/bash for N in quan zhi qiang do if [ `expr length $N ...