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. this.$set用法

    this.$set()的主要功能是解决改变数据时未驱动视图的改变的问题,也就是实际数据被改变了,但我们看到的页面并没有变化,这里主要讲this.$set()的用法,如果你遇到类似问题可以尝试下,vue ...

  2. 集合概述&集合之List接口

    集合与数组存储概述 集合.数组都是对多个数据进行存储操作的结构,简称Java容器.此时的存储,主要指的是内存层面的存储,不涉及到持久化的存储(.txt,.jpg,.avi,数据库中) 数组存储的特点: ...

  3. webpack 之开发环境优化 HMR

    webpack 之开发环境优化 HMR // webpack.config.js /** * HMR hot module replacement 热模块替换 / 模块热替换 * 作用:一个模块发生变 ...

  4. Part 34 AngularJS controller as vs scope

    There are 2 ways to expose the members from the controller to the view - $scope and CONTROLLER AS. T ...

  5. 测试开发【提测平台】分享14-Vue图标Icon几种用法并利用其一优化菜单

    微信搜索[大奇测试开],关注这个坚持分享测试开发干货的家伙. 回归主线更新,由于本次知识点只有一个,就不给思维导图了,在上系列测试平台开发实践中主要学习了页面直接的转跳方法和远程搜索的如何做,最终实现 ...

  6. Java设计模式之(二)——工厂模式

    1.什么是工厂模式 Define an interface for creating an object,but let subclasses decide which class toinstant ...

  7. 04373 C++程序设计 2019版 第一章习题五、程序设计题

    题目: 1.编写一个程序,将从键盘输入的n个字符串保存在一个一维数组A中.在输入字符串之前,先输入n的值.要求,数组A需要动态申请空间,程序运行结束前再释放掉. #include <iostre ...

  8. [zoj3990]Tree Equation

    记$dep(T)$为树$T$的深度(根节点深度为0),则有$\begin{cases}dep(A+B)=\max(dep(A),dep(B))\\dep(A\cdot B)=dep(A)+dep(B) ...

  9. [hdu6581]Vacation

    首先发现,最终第0辆车一定被堵在某一辆车前,那么等价于它的初始位置就在(那辆车的位置+中间车的车长)/那辆车的速度,其中最大的那个就是答案因此得出结论:$ans=max((\sum_{j=1}^{i} ...

  10. [cf1285F]Classical

    先枚举$d=\gcd$,然后暴力枚举所有$d$的倍数,相当于求出若干个数中最大的互素对 假设选出的数依从大到小排序后为$a_{i}$,令$g_{i}=\min_{(a_{i},a_{j})=1}j$, ...