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的更多相关文章

  1. 转 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 ...

  2. Rust 中的继承与代码复用

    在学习Rust过程中突然想到怎么实现继承,特别是用于代码复用的继承,于是在网上查了查,发现不是那么简单的. C++的继承 首先看看c++中是如何做的. 例如要做一个场景结点的Node类和一个Sprit ...

  3. Rust入坑指南:千人千构

    坑越来越深了,在坑里的同学让我看到你们的双手! 前面我们聊过了Rust最基本的几种数据类型.不知道你还记不记得,如果不记得可以先复习一下.上一个坑挖好以后,有同学私信我说坑太深了,下来的时候差点崴了脚 ...

  4. Rust 基础学习

    所有权: 变量具有唯一所有权.如果一个类型拥有 Copy trait,一个旧的变量在将其赋值给其他变量后仍然可用.除此之外,赋值意味着转移所有权.Rust 不允许自身或其任何部分实现了 Drop tr ...

  5. [易学易懂系列|rustlang语言|零基础|快速入门|(11)|Structs结构体]

    [易学易懂系列|rustlang语言|零基础|快速入门|(11)] 有意思的基础知识 Structs 我们今天来看看数据结构:structs. 简单来说,structs,就是用来封装相关数据的一种数据 ...

  6. rust实战系列 - 使用Iterator 迭代器实现斐波那契数列(Fibonacci )

    为什么是斐波那契数列 斐波那契数列十分适合用来实战rust的迭代器,算法也很简单,一目了然.这个例子可以用来学习Iterator的使用,十分适合刚学习了rust的迭代器章节后用来练练手. 代码实战 d ...

  7. Rust 中的数据布局-repr

    repr(Rust) 首先,所有类型都有一个以字节为单位的对齐方式,一个类型的对齐方式指定了哪些地址可以用来存储该值.一个具有对齐方式n的值只能存储在n的倍数的地址上.所以对齐方式 2 意味着你必须存 ...

  8. Rust语言的多线程编程

    我写这篇短文的时候,正值Rust1.0发布不久,严格来说这是一门兼具C语言的执行效率和Java的开发效率的强大语言,它的所有权机制竟然让你无法写出线程不安全的代码,它是一门可以用来写操作系统的系统级语 ...

  9. Rust初步(七):格式化

    在Rust中,如果要进行屏幕输出,或者写入到文件中,需要对数据进行格式化.这一篇总结一下它所支持的几种格式化方式. 这篇文章参考了以下官方文档,不过,按照我的风格,我还是会突出于C#语言的比较,这样可 ...

随机推荐

  1. redis客户端修改了key-value对之后有时会报MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist o...错误,不能持久化

    解决方案,连接redis客户端 redis目录下:redis-cli -h 127.0.0.1 -p 6379-h后为redis服务器ip,-p后为端口号进入redis-client之后输入命令 co ...

  2. Idea tomcat debug按钮灰色无法运行

    打开Project Structure 2.选中src,点击按钮关闭界面,重启idea即可

  3. Visual Studio中使用Macros插件给代码添加注释、时间和以及自动脚本

    title: Visual Studio中使用Macros插件给代码添加注释.时间和以及自动脚本 date: 2020-09-11 sidebarDepth: 2 tags: 代码 Visual st ...

  4. 美妙绝伦面向node引用-zico图标(逐浪矢量全真图标)1.9发布

    15年前,那个农村小伙初入广告行业被讥笑没有审美 于是他狠下决心,积极研发,缔就技术之核, 再后来,那些PPT和美工er们随便怎么自好,无法让其心怵. 因为他是中华人民共和国唯一具备web.cms.o ...

  5. CSS学习笔记:flex布局

    目录 一.Flex布局简介 1. Flex布局的主要作用 2. Flex布局应用场景 二.Flex布局的使用 1. Flex布局的两种相关元素 2. 父项属性 2.1 flex- direction ...

  6. 『学了就忘』Linux软件包管理 — 44、在RPM包中提取文件

    目录 1.RPM包中文件的提取 2.在RPM包中提取文件的操作 (1)cpio命令介绍 (2)提取RPM包中文件 1.RPM包中文件的提取 为什么要做这个事呢? 在操作Linux系统的时候误删除一个文 ...

  7. 查看python是32位,还是64位

    步骤:cmd打开命令行,输入python,查看. 如果32bit,则是32位:如果是64,则是64位 如果需要安装客户端进行orcale数据库操作,则要保证python\

  8. OpenShift 本地开发环境配置(基于 Minishift)

    本文要做什么? 很多为了验证应用在 OpenShift 平台的行为是否正常,或者组成一个简单的开发环境,直接搭建一个 OpenShift/Origin 环境可能太重了,而且运行在本机可能占用内存也太多 ...

  9. 了解Threejs中的Clock对象以及简单应用

    什么是Clock对象 如果你对 JavaScript 有一定了解,那么 JavaScript 的时间对象 Date 你一定不陌生,Clock 本质上就是对 Date 进行封装,提供了一些方法和属性 当 ...

  10. CF513G3 Inversions problem

    考虑记\(f_{i,j,k}\)为\(k\)次操作后,\(i,j\)位置被调换的概率. 那么我们考虑枚举我们要算的答案即\((x,y)\). 那么有\(\frac{n * (n + 1)}{2}\)种 ...