@[TOC](研读Rust圣经解析——Rust learn-7(结构体与枚举,Option))
结构体
结构体和我们在“元组类型”部分论过的元组类似,它们都包含多个相关的值。和元组一样,结构体的每一部分可以是不同类型。但不同于元组,结构体需要命名各部分数据以便能清楚的表明其值的意义。由于有了这些名字,结构体比元组更灵活:不需要依赖顺序来指定或访问实例中的值。
声明结构体
我们通过使用struct关键字对结构体进行声明,指定结构体中的字段类型
struct User{
id:i32,
username:String,
pwd:String,
}
构造结构体实例
如下,我们在声明结构体后在代码中进行构建使用
#[derive(Debug)]
struct User {
id: i32,
username: String,
pwd: String,
}
fn main() {
let user = User {
id: 1,
username: "zhangsan".to_string(),
pwd: "123455".to_string(),
};
println!("{:#?}", user);
}
访问结构体中的字段
这很简单结构体名称.字段名称
即可访问了
fn main() {
let user = User {
id: 1,
username: "zhangsan".to_string(),
pwd: "123455".to_string(),
};
println!("{:?}", user.username);
}
元组结构体
定义与元组类似的结构体,称为 元组结构体(tuple structs)。元组结构体有着结构体名称提供的含义,但没有具体的字段名,只有字段的类型。当你想给整个元组取一个名字,并使元组成为与其他元组不同的类型时,元组结构体是很有用的,这时像常规结构体那样为每个字段命名就显得多余和形式化了。
好比我要定义一个坐标点:
struct Pos(f64, f64);
类单元结构体
其实就是一个简单的空结构体,里面没有任何字段,用于实现trait你可以将其理解为一个可供实现的继承体
struct UnitStruct;
为结构体赋予方法
我们通过使用impl关键为结构体内添加结构体需要的方法
例如以下,我们声明了一个User结构体,为结构体添加了一个new方法以构建一个结构体
#[derive(Debug)]
struct User {
id: i32,
username: String,
pwd: String,
}
impl User {
fn new(id: i32, username: String, pwd: String) -> User {
return User {
id,
username,
pwd,
};
}
}
使用结构体中声明的方法
如果你是直接使用结构体的话,调用其中的方法就需要使用::
fn main() {
let user =User::new(1,"zhangsan".to_string(),"sdjk".to_string());
println!("{:#?}", user);
}
self调用自身
如下一段程序中sout方法的参数是&self也就是调用了自身,我们在函数中就可以直接使用self获取字段,self只取决于你的结构体方法、字段有哪些。
impl User {
fn new(id: i32, username: String, pwd: String) -> User {
return User {
id,
username,
pwd,
};
}
fn sout(&self) -> String {
return self.username.to_string() + "---" + &self.pwd;
}
}
fn main() {
let user = User::new(1, "zhangsan".to_string(), "sdjk".to_string());
println!("{:#?}", user);
println!("{}", user.sout());
}
枚举
枚举(enum)允许你通过列举可能的 成员(variants)来定义一个类型
定义枚举
如下我们定义了一个父母的枚举,使用enum关键字
enum Parent{
father,mother
}
使用枚举中的成员
如下,使用::
即可指定成员
let wang = Parent::father;
为枚举定义方法
其实这和struct中是一样的也是使用impl关键字
enum Parent {
father,
mother,
}
impl Parent {
fn getFather() -> Parent {
return Parent::father;
}
}
let wang = Parent::getFather();
self
使用self其实也和结构体一样的
#[derive(Debug)]
enum Parent {
father,
mother,
}
impl Parent {
fn getFather() -> Parent {
return Parent::father;
}
fn sss (&self)->(){
println!("{:?}", self::father)
}
}
fn main(){
let wang = Parent::getFather();
wang.sss();
}
相互嵌套
我们既可以在结构体里嵌套枚举也可以在枚举中使用结构体
枚举嵌套结构体
我们构建一个Person结构体,嵌套入Parent中,以下是一个较为完整的示例:
#[derive(Debug)]
struct Person {
name: String,
age: i32,
height: f64,
weight: f64,
}
#[derive(Debug)]
enum Parent {
father {
name: String,
age: i32,
},
mother(Person),
}
impl Parent {
fn getFather(&self) -> Parent {
return self::father {
name: "zhansgan".to_string(),
age: 26,
};
}
}
fn main() {
let wang = Parent::mother(Person {
name: "wang".to_string(),
age: 26,
height: 167.6,
weight: 104.5,
});
println!("{:#?}", wang);
let li = Parent::father {
name: "li".to_string(),
age: 32,
};
println!("{:?}", li);
println!("{:?}",li.getFather());
}
结构体中嵌套枚举
这个示例就很简单了,将Unit作为类型给到了结构体中的字段
struct HtmlUnit {
unit: Unit,
}
enum Unit {
px,
vh,
vw,
}
Option
Option 是标准库定义的另一个枚举。Option 类型应用广泛因为它编码了一个非常普遍的场景,即一个值要么有值要么没值。Rust 并没有很多其他语言中有的空值功能。空值(Null )是一个值,它代表没有值。在有空值的语言中,变量总是这两种状态之一:空值和非空值。
空值的问题在于当你尝试像一个非空值那样使用一个空值,会出现某种形式的错误。因为空和非空的属性无处不在,非常容易出现这类错误。
然而,空值尝试表达的概念仍然是有意义的:空值是一个因为某种原因目前无效或缺失的值。
问题不在于概念而在于具体的实现。为此,Rust 并没有空值,不过它确实拥有一个可以编码存在或不存在概念的枚举。这个枚举是Option<T>
enum Option<T> {
None,
Some(T),
}
Some
Option中的Some值可以将一个值构建为Option<type>
返回使用unwrap系列可以还原出来
fn main() {
let a: Option<String> = Some(String::from("nihao"));
println!("{}", a.unwrap())
}
None
在对Option<T>
进行运算之前必须将其转换为 T。通常这能帮助我们捕获到空值最常见的问题之一:假设某值不为空但实际上为空的情况。
消除了错误地假设一个非空值的风险,会让你对代码更加有信心。为了拥有一个可能为空的值,你必须要显式的将其放入对应类型的Option<T>
中。接着,当使用这个值时,必须明确的处理值为空的情况。只要一个值不是 Option<T>
类型,你就 可以 安全的认定它的值不为空。
let b: Option<i32> = None;