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#语言的比较,这样可 ...
随机推荐
- Centos6.8 yum报错及修复YumRepo Error: All mirror URLs are not using ftp, http[s] or file. Eg. Invalid
问题 使用yum安装软件时报错 YumRepo Error: All mirror URLs are not using ftp, http[s] or file. Eg. Invalid relea ...
- Linux ns 6. Network Namespace 详解
文章目录 1. 简介 1.1 Docker Network 桥接模式配置 2. 代码解析 2.1 copy_net_ns() 2.2 pernet_list 2.2.1 loopback_net_op ...
- layui表格-template模板的三种用法
问题情境: layui中将数据库数据通过layui table渲染到前端表格,非常简单,但是如果数据库存储的信息不能被直接展示,项目中该页面有好几个这样的字段,会员类型,支付类型,会员时长还有平台类型 ...
- Django笔记&教程 1-1 一 新建项目
Django 自学笔记兼学习教程第1章第1节--一 新建项目 点击查看教程总目录 1- 命令行新建Django项目 新建项目命令(project_name处为项目名) django-admin sta ...
- 九. Go并发编程--context.Context
一. 序言 前几篇中提到 等待多个 goroutine 协作的方式可以使用WaitGroup. 但是有一种场景我们无论是使用Mutex, sync/Once,都无法满足. 场景如下 现在有一个 Ser ...
- 5.0jemter(英文版)录制脚本,进行压力测试
压力测试的目的:找到瓶颈.优化速率 1.jemter,Test Plan-->>Add-->>Threds(users)-->>Thred Group创建线程组 2 ...
- 不可忽视的Dubbo线程池
问题描述 线上突然出现Dubbo超时调用,时间刚好为Consumer端设置的超时时间. 有好几个不同的接口都报超时了 第1次调用超时,第2次(或第3次)重试调用非常快(正常水平) Dubbo调用超时的 ...
- 剖析虚幻渲染体系(12)- 移动端专题Part 3(渲染优化)
目录 12.6 移动端渲染优化 12.6.1 渲染管线优化 12.6.1.1 使用新特性 12.6.1.2 管线优化 12.6.1.3 带宽优化 12.6.2 资源优化 12.6.2.1 纹理优化 1 ...
- [hdu6582]Path
首先,从1和n跑一次dij,判断每一条边能否出现在最短路上,不能出现就删掉,然后将所有边建在图上,流量为边权,跑最小割即可. 1 #include<bits/stdc++.h> 2 usi ...
- [atAGC020E]Encoding Subsets
令$f_{S}$表示字符串$S$的答案(所有子集的方案数之和),考虑转移: 1.最后是一个字符串,不妨仅考虑最后一个字符,即$f_{S[1,|S|)}$(字符串下标从1开始),特别的,若$S_{|S| ...