Rust入门-11-枚举

枚举

通过列举可能的 成员variants) 来定义一个类型

定义枚举

eg:IP 地址,目前被广泛使用的两个主要 IP 标准:IPv4(version four)和 IPv6(version six)。

一个 IP 地址要么是 IPv4 的要么是 IPv6 的,而且只能是其中一个。

枚举值只能是枚举中一个成员。

通过定义一个 IpAddrKind 枚举来列出 IP 地址可能的类型是V4 还是 V6

enum IpAddrKind {
    V4,
    V6,
}      //定义后IpAddrKind就是可以使用的自定义数据类型了

枚举值

创建 IpAddrKind 两个不同成员的实例:

let four = IpAddrKind::V4; 
let six = IpAddrKind::V6;   

定义一个函数来获取任何 IpAddrKind

fn route(ip_type: IpAddrKind) { }

使用任一成员来调用这个函数:

route(IpAddrKind::V4); 
route(IpAddrKind::V6);

enum{
    V4,
    V6
}
int main() {
    let four = IpAddrKind::V4; 
	let six = IpAddrKind::V6; 
    
    route(IpAddrKind::V4); 
	route(IpAddrKind::V6);
  //还可以
  //route(four);
  //route(six);  
}
fn route(ip_type: IpAddrKind) { }

将数据附加到枚举的变体中

enum IpAddrKind {
        V4,
        V6,
    }

struct IpAddr {
    kind: IpAddrKind,   
    address: String,   //address  ip地址
}
fn main() {    
    let home = IpAddr {
        kind: IpAddrKind::V4,
        address: String::from("127.0.0.1"),
    };

    let loopback = IpAddr {
        kind: IpAddrKind::V6,
        address: String::from("::1"),
    };
}

Rust可以使用枚举将数据直接放进每一个枚举成员

enum IpAddr {
    V4(String),  //V4与V6的值的变量是字符串
    V6(String),
}

let home = IpAddr::V4(String::from("127.0.0.1"));
let loopback = IpAddr::V6(String::from("::1"));
  • 这样就不需要额外的结构体

  • 每个枚举成员可以处理不同类型和数量的数据

enum IpAddr {
    V4(u8, u8, u8, u8),   //IPv4 版本的 IP 地址总是含有四个值在 0 和 255 之间的数字部分
    V6(String),
}

let home = IpAddr::V4(127, 0, 0, 1);
let loopback = IpAddr::V6(String::from("::1"));

标准库中的 IpAddr

struct Ipv4Addr {
    // --snip--
}

struct Ipv6Addr {
    // --snip--
}

enum IpAddr {
    V4(Ipv4Addr),   //V4与V6为结构体类型
    V6(Ipv6Addr),
}

即可以将任意类型数据放入枚举成员

另一个枚举也可以作为枚举成员

enum Message {
    Quit,                       //Quit 没有关联任何数据
    Move { x: i32, y: i32 },    //Move 包含一个匿名结构体
    Write(String),              // Write 包含单独一个 String
    ChangeColor(i32, i32, i32), //ChangeColor 包含三个 i32
}

为枚举定义方法

可以使用 impl 定义方法(与结构体类似)

impl Message {
    fn call(&self) {   //self为借用
        // 在这里定义方法体
    }
}

let m = Message::Write(String::from("hello"));
m.call();

通过self获取调用方法的值,当 m.call() 运行时 call 方法中的 self 的值就是m

Rust中不存在Null

在其他语言中,null是一个值,表示"没有值"

一个变量可以处于两种状态:空值、非空值

null的问题在于:当尝试使用非null值那样使用null值时,就会引起某种错误

eg:在C#中

string a=null;
string b=a+"12345"// a 与 b 是两种不同的类型
                   //编译时可能会发生错误

null可以描述因某种原因变为无效或缺失的值

Option枚举

Option 是标准库定义的另一个枚举,而且是在Prelude(预导入模块)中

option枚举描述一个值要么有值要么没值的情况

Rust拥有一个类似Null概念的枚举Option<T>

//Option<T>在标准库中的定义
enum Option<T> {  
    Some(T),
    None,
}

<T> 语法是一个泛型类型参数

Option<T> 枚举是 prelude (预导入模块)中,不需要将其显式引入作用域,可以直接使用。其成员也可以直接使用,可以不需要 Option:: 前缀来直接使用 SomeNone

不过Option<T> 也仍是常规的枚举,Some(T)None 仍是 Option<T> 的成员。

let some_number = Some(5);
let some_string = Some("a string");

let absent_number: Option<i32> = None;

使用None时需要告诉 Option<T> 是什么类型的,因为编译器只通过None值无法推断出Some 成员保存的值的类型

Option<T>较Null的好处

Option<T>T(这里 T 可以是任何类型)是不同的类型,不可以把 Option<T> 直接当成 T

let x: i8 = 5;
let y: Option<i8> = Some(5);

let sum = x + y;

该代码不能编译

该代码尝试将Option<i8>i8 相加,但是两者类型不同,不可以相加

那么要想对 Option<T> 进行 T 的运算之前必须将其转换为 T

即在Rust中只要这个值不为 Option<T> ,就可以安全地假设该值不为空

posted @   ragworm  阅读(39)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示