首页 > 其他分享 >猿创征文 | 【Rust指南】解析struct 结构体的定义、实例化、方法、所有权、关联函数

猿创征文 | 【Rust指南】解析struct 结构体的定义、实例化、方法、所有权、关联函数

时间:2022-11-21 11:35:01浏览次数:55  
标签:u32 猿创 struct self 实例 Rust Rectangle 结构


猿创征文 | 【Rust指南】解析struct 结构体的定义、实例化、方法、所有权、关联函数_字段

文章目录

  • ​​  前言​​
  • ​​一、结构体的定义​​
  • ​​二、结构体实例化​​
  • ​​三、元组结构体​​
  • ​​四、结构体所有权​​
  • ​​五、结构体方法​​
  • ​​六、结构体关联函数​​

  书接上文,本篇博客要分享的是Rust 中和结构体有关的知识,包括定义、实例化的特点,方法的格式、所有权问题以及关联函数。所以此篇文章还会涉及到前面讲的Rust 基本数据类型、所有权等知识,大家在对某些知识点感到陌生的时候可以参考此专栏以往的文章。


一、结构体的定义

Rust 中的结构体与元组(Tuple)都可以将若干个类型不一定相同的数据捆绑在一起形成整体,但结构体的每个成员和其本身都有一个名字,这样设计有利于访问其成员。元组常用于非定义的多值传递,而结构体用于规范常用的数据结构,且结构体内的成员被称为字段

结构体定义的语法:

struct User{
username:String,
sex:String,
age:u32,
height:u32
}
  • 乍一看跟C/C++很相似,但是Rust里的结构体每定义一个字段都要加上逗号且最后一个字段不需要加任何符号。
  • 每个字段需要指定具体的数据类型。
  • 同时值得注意的是:结构体不允许在定义的时候实例化。 我们知道​​C/C++​​语言是可以在最后的大括号后面实例化的,但是Rust没有这一特点且大括号后面不能加分号。

二、结构体实例化

Rust 很多地方受 ​​JavaScript​​​ 影响,在实例化结构体的时候用 JSON 对象的 ​​key: value​​ 语法来实现定义:

  • 为每个字段指定具体值
  • 无需按照声明的顺序指定

例如:

let demo=User{
username: String::from("微凉秋意"),
sex: String::from("男"),
age:22,
height:183
};

记住一般格式:

结构体类名 {
字段名 : 字段值,

}


如果正在实例化的结构体有字段名称和现存变量名称一样的,可以简化书写:

let username=String::from("微凉秋意");
let sex=String::from("男");
let demo=User{
username, // 等同于 username : username,
sex,
age:22,
height:183
};

有这样一种情况:你想要新建一个结构体的实例,其中大部分属性需要被设置成与现存的一个结构体属性一样,仅需更改其中的一两个字段的值,可以使用结构体更新语法:

let demo1=User{
username:String::from("叶落秋白"),
sex:demo.sex.clone(),
..demo
};

注意:

  • ​..demo​​ 后面不可以有逗号。这种语法不允许一成不变的复制另一个结构体实例,意思就是说至少重新设定一个字段的值才能引用其他实例的值。
  • ​sex:demo.sex.clone()​​​这里如果不单独写出来编译器会报错:​​borrow of moved value​
  • 猿创征文 | 【Rust指南】解析struct 结构体的定义、实例化、方法、所有权、关联函数_后端_02

  • 意思就是租借了没有所有权的变量,由于无法租借所有权,报错也很正常。而导致错误的原因就是​​demo.sex​​的所有权已经在赋值的时候转移给了​​demo1.sex​​,这点要尤其注意。因此写成​​demo.sex.clone()​​就可以解决所有权转移的问题了。
  • 如果想要修改实例的成员属性,需要在定义的时候把结构体改为可变,也就是加上​​mut​​关键字
  • 一旦struct实例是可变的,那么实例中所有的字段都是可变的
  • 无法单独为某一个字段设置为可变

三、元组结构体

元组结构体是一种形式是元组的结构体,与元组的区别是它有名字和固定的类型格式。
它存在的意义是为了处理那些需要定义类型(经常使用)又不想太复杂的简单数据:

//定义:
struct Color(u8,u8,u8);
struct Point(u8,u8,u8);
//实例:
let black=Color(0,0,0);
let origin=Point(0,0,0);
  • 上面定义的​​black​​​和​​origin​​尽管字段类型一致,但是二者是不同的类型,属于两个元组结构体实例。
  • 访问元组结构体与访问元组方法一致,通过点标记法即可

补充一个特殊的单元结构体

例如:

struct UnitStruct;

我们称这种没有身体的结构体为单元结构体(​​Unit Struct​​)

  • 可以定义没有任何字段的struct
  • 适用于需要在某个类型上实现某个​​trait​​(接口,没有具体实现)

四、结构体所有权

结构体必须掌握字段值所有权,因为结构体失效的时候会释放所有字段。

  • 这也是上面字符串类型使用​​String​​​而不是用​​&str​​(字符串切片)的原因
  • 不过结构体是可以定义引用类型字段的,这需要结合后面的”生命周期“实现

五、结构体方法

Rust中 的方法和函数类似,只不过它是用来操作结构体实例的。在C++语言中,我们知道类内的​​this​​指针指向的是对象自身,而Rust 语言不是面向对象的,从它所有权机制的创新可以看出这一点。但是面向对象的珍贵思想可以在 Rust 实现。

结构体方法的第一个参数必须是 ​​&self​​,不需声明类型,因为 self 不是一种风格而是关键字

计算一个矩形的面积的方法:

#[derive(Debug)]
struct Rectangle{
width:u32,
length:u32
}
impl Rectangle {
fn area(&self)->u32{
self.width*self.length
}
}
fn main(){
let rect=Rectangle{
width:15,
length:20
};
println!("rect.area={}",rect.area());
println!("rect = {:#?}",rect);
}
  • 这里的​​#[derive(Debug)]​​是Rust提供的调试库
  • 在程序前面加上之后在​​println​​​和​​print​中就可以用 ​​{:?}​​​或​​{:#?}​​ 占位符输出一整个结构体
  • 不带​​#​​的占位符是输出一行,而带的占位符输出和实例化一样形式的结构体
  • 为结构体添加方法需要在​​impl​​​里进行,格式就是​​impl+结构体类型{}​
  • 在调用结构体方法的时候不需要填写 ​​self​​ ,这是出于对使用方便性的考虑。

一个多参数的例子:

struct Rectangle {
width: u32,
height: u32,
}

impl Rectangle {
fn area(&self) -> u32 {
self.width * self.height
}

fn wider(&self, rect: &Rectangle) -> bool {
self.width > rect.width
}
}

fn main() {
let rect1 = Rectangle { width: 30, height: 50 };
let rect2 = Rectangle { width: 40, height: 20 };

println!("{}", rect1.wider(&rect2));
}
//运行结果为false,证明rect1没有rect2宽度大

六、结构体关联函数

之所以"结构体方法"不叫"结构体函数"是因为"函数"这个名字留给了这种函数:它在 ​​impl​​​ 块中没有 ​​&self​​ 参数。

这种函数不依赖实例,但是使用它需要声明是在哪个 ​​impl​​ 块中的。

一直使用的 ​​String::from​​ 函数就是一个"关联函数"。

接下来看一个实例:

#[derive(Debug)]
struct Rectangle {
width: u32,
height: u32,
}

impl Rectangle {
fn create(width: u32, height: u32) -> Rectangle {
Rectangle { width, height }
}
}

fn main() {
let rect = Rectangle::create(30, 50);
println!("{:?}", rect);
}

可以看到在​​Rectangle​​​块中定义了一个​​create​​​函数,返回值是一个​​Rectangle​​​类型,而内部实现就是实例化结构体的一个过程。那么这时候在主函数调用该关联函数就可以创建不同的​​Rectangle​​结构体实例了。


​Rust结构体有关的知识分享就到此结束了,感觉写的对你的口味就给博主点赞关注吧,你的支持是我更文的不竭动力!​


标签:u32,猿创,struct,self,实例,Rust,Rectangle,结构
From: https://blog.51cto.com/u_15778815/5873180

相关文章

  • rust struct 初始化的语法糖 - struct update syntax
    rust语法提供了..操作符来实现struct更新的语法糖,参见StructUpdatesyntax。废话少说,直接定义一个学生的struct:#[derive(Default,Debug)]structStudent{age:......
  • socket模块实现网络编程及struct模块解决黏包问题
    目录一、socket模块1、简介2、基于文件类型的套接字家族3、基于网络类型的套接字家族二、socket代码简介三、socket代码优化1.聊天内容自定义2.让聊天循环起来3.用户输入的......
  • Rust实战系列-生命周期、所有权和借用
    本文是《Rustinaction》学习总结系列的第四部分,更多内容请看已发布文章:一、Rust实战系列-Rust介绍二、Rust实战系列-基本语法三、Rust实战系列-复合数据类型“理解......
  • Rust实战系列-深入理解数据
    本文是《Rustinaction》学习总结系列的第五部分,更多内容请看已发布文章:一、Rust实战系列-Rust介绍二、Rust实战系列-基本语法三、Rust实战系列-复合数据类型四、Rust......
  • 基础知识/RUST程序设计语言/4.认识所有权
    //本页是对RUST第四章的学习汇总记录。书址4.1.什么是所有权1.所有权是RUST语言的核心功能(之一)他是一种管理内存的方式2.**所有权规则Rust中的每一个值都......
  • MapStruct的使用
    目录​​pom.xml​​​​在不使用lombok的情况下使用mapstruct​​​​同时使用lombok、mapstruct​​​​基本使用​​​​作为bean注入​​​​自定义类型转换​​​......
  • Rust cargo镜像加速
    推荐使用科大的注册服务来提升拉取依赖的速度,地址:https://mirrors.ustc.edu.cn/help/crates.io-index.html1.部分依赖镜像支持【也就是添加一个镜像地址,在拉取依赖的......
  • 黏包现象及struct模块
    目录黏包现象struct模块解决黏包现象黏包代码实操UDP协议(了解)黏包现象黏包现象1.服务端连续执行三次recv2.客户端连续执行三次send执行上述两端的操作,服务端一次性......
  • windows 进程 Shell Infrastructure Host 占用CPU,以及大量使用电源。
    表现:风扇疯狂的转,声音超大,电脑发热严重。解决:进入任务管理器,可以看到进程ShellInfrastructureHost高耗电,占用CPU很多。解决方案见:shellinfrastructureh......
  • Rust库学习-cipher(简单使用)
    介绍cipher是Rust的一个密码库实践Cargo.toml[dependencies]aes="0.8.2"base64="0.13.1"cipher="0.4.3"main.rsuseaes::cipher::{generic_array::Generic......