边做边学Rust之用户自定义类型

3 用户自定义类型

Rust自定义类型主要通过下面两个关键进行定义:

  • struct:定义一个结构
  • enum:定义一个枚举

常量能以通过const和static关键字创建。

3.1 结构

有三种类型的结构(“structs”),可以使用struct关键字来创建:

  • 元组结构体,又名元组
  • 传统C结构体
  • 元结构体,无field,为了做成通用类型
// A unit struct
struct Nil;

// A tuple struct
struct Pair(i32, f64);

// A struct with two fields
struct Point {
    x: f64,
    y: f64,
}

// Structs can be reused as fields of another struct
#[allow(dead_code)]
struct Rectangle {
    p1: Point,
    p2: Point,
}

fn main() {
    // Instantiate a `Point`
    let point: Point = Point { x: 0.3, y: 0.4 };

    // Access the fields of the point
    println!("point coordinates: ({}, {})", point.x, point.y);

    // Destructure the point using a `let` binding
    let Point { x: my_x, y: my_y } = point;

    let _rectangle = Rectangle {
        // struct instantiation is an expression too
        p1: Point { x: my_y, y: my_x },
        p2: point,
    };

    // Instantiate a unit struct
    let _nil = Nil;

    // Instantiate a tuple struct
    let pair = Pair(1, 0.1);

    // Destructure a tuple struct
    let Pair(integer, decimal) = pair;

    println!("pair contains {:?} and {:?}", integer, decimal);
}

程序执行结果:

point coordinates: (0.3, 0.4)
pair contains 1 and 0.1

3.2 枚举

enum关键字允许创建一个可能有许多变体的变量。每一个对结构体来说是合法的变体,对枚举同样是合法的。

// An attribute to hide warnings for unused code.
#![allow(dead_code)]

// Create an `enum` to classify someone. Note how both names
// and type information together specify the variant:
// `Skinny != Fat` and `Height(i32) != Weight(i32)`. Each
// is different and independent.
enum Person {
    // An `enum` may either be `unit-like`,
    Skinny,
    Fat,
    // like tuple structs,
    Height(i32),
    Weight(i32),
    // or like structures.
    Info { name: String, height: i32 }
}

// A function which takes a `Person` enum as an argument and
// returns nothing.
fn inspect(p: Person) {
    // Usage of an `enum` must cover all cases (irrefutable)
    // so a `match` is used to branch over it.
    match p {
        Person::Skinny    => println!("Is skinny!"),
        Person::Fat       => println!("Is fat!"),
        // Destructure `i` from inside the `enum`.
        Person::Height(i) => println!("Has a height of {}.", i),
        Person::Weight(i) => println!("Has a weight of {}.", i),
        // Destructure `Info` into `name` and `height`.
        Person::Info { name, height } => {
            println!("{} is {} tall!", name, height);
        },
    }
}

fn main() {
    let person = Person::Height(18);
    let danny  = Person::Weight(10);
    // `to_owned()` creates an owned `String` from a string slice.
    let dave   = Person::Info { name: "Dave".to_owned(), height: 72 };
    let john   = Person::Fat;
    let larry  = Person::Skinny;

    inspect(person);
    inspect(danny);
    inspect(dave);
    inspect(john);
    inspect(larry);
}

程序运行结果:

Has a height of 18.
Has a weight of 10.
Dave is 72 tall!
Is fat!
Is skinny!

3.2.1 use

可以使用use声明,所以不用手动指定作用域:

// An attribute to hide warnings for unused code.
#![allow(dead_code)]

enum Status {
    Rich,
    Poor,
}

enum Work {
    Civilian,
    Soldier,
}

fn main() {
    // Explicitly `use` each name so they are available without
    // manual scoping.
    use Status::{Poor, Rich};
    // Automatically `use` each name inside `Work`.
    use Work::*;

    // Equivalent to `Status::Poor`.
    let status = Poor;
    // Equivalent to `Work::Civilian`.
    let work = Civilian;

    match status {
        // Note the lack of scoping because of the explicit `use` above.
        Rich => println!("The rich have lots of money!"),
        Poor => println!("The poor have no money..."),
    }

    match work {
        // Note again the lack of scoping.
        Civilian => println!("Civilians work!"),
        Soldier  => println!("Soldiers fight!"),
    }
}

程序执行结果:

The poor have no money...
Civilians work!

3.2.2 C-like

enum也能像C预言的枚举那样使用。

// An attribute to hide warnings for unused code.
#![allow(dead_code)]

// enum with implicit discriminator (starts at 0)
enum Number {
    Zero,
    One,
    Two,
}

// enum with explicit discriminator
enum Color {
    Red = 0xff0000,
    Green = 0x00ff00,
    Blue = 0x0000ff,
}

fn main() {
    // `enums` can be cast as integers.
    println!("zero is {}", Number::Zero as i32);
    println!("one is {}", Number::One as i32);

    println!("roses are #{:06x}", Color::Red as i32);
    println!("violets are #{:06x}", Color::Blue as i32);
}

程序运行结果为:

zero is 0
one is 1
roses are #ff0000
violets are #0000ff

3.2.3 测试用例:链表

enums一个普通的使用时创建链表:

use List::*;

enum List {
    // Cons: Tuple struct that wraps an element and a pointer to the next node
    Cons(u32, Box<List>),
    // Nil: A node that signifies the end of the linked list
    Nil,
}

// Methods can be attached to an enum
impl List {
    // Create an empty list
    fn new() -> List {
        // `Nil` has type `List`
        Nil
    }

    // Consume a list, and return the same list with a new element at its front
    fn prepend(self, elem: u32) -> List {
        // `Cons` also has type List
        Cons(elem, Box::new(self))
    }

    // Return the length of the list
    fn len(&self) -> u32 {
        // `self` has to be matched, because the behavior of this method
        // depends on the variant of `self`
        // `self` has type `&List`, and `*self` has type `List`, matching on a
        // concrete type `T` is preferred over a match on a reference `&T`
        match *self {
            // Can't take ownership of the tail, because `self` is borrowed;
            // instead take a reference to the tail
            Cons(_, ref tail) => 1 + tail.len(),
            // Base Case: An empty list has zero length
            Nil => 0
        }
    }

    // Return representation of the list as a (heap allocated) string
    fn stringify(&self) -> String {
        match *self {
            Cons(head, ref tail) => {
                // `format!` is similar to `print!`, but returns a heap
                // allocated string instead of printing to the console
                format!("{}, {}", head, tail.stringify())
            },
            Nil => {
                format!("Nil")
            },
        }
    }
}

fn main() {
    // Create an empty linked list
    let mut list = List::new();

    // Append some elements
    list = list.prepend(1);
    list = list.prepend(2);
    list = list.prepend(3);

    // Show the final state of the list
    println!("linked list has length: {}", list.len());
    println!("{}", list.stringify());
}

程序运行结果:

linked list has length: 3
3, 2, 1, Nil

3.3 常量

Rust有两种不同类型的常量,这些常量可以在任何作用于定义,包括全局。两种方法都需要显示声明:

  • const:一个不可改变的值(通常用法)
  • static:一个可能在staic声明周期内可变的变量

“string”是一个特例。它可以直接赋值给一个static变量,而不需要修改,因为它的类型签名:&‘static str已经使用了‘static生命周期。所有其他的引用类型必须使用‘static声明走起做特殊注解。

// Globals are declared outside all other scopes.
static LANGUAGE: &'static str = "Rust";
const  THRESHOLD: i32 = 10;

fn is_big(n: i32) -> bool {
    // Access constant in some function
    n > THRESHOLD
}

fn main() {
    let n = 16;

    // Access constant in the main thread
    println!("This is {}", LANGUAGE);
    println!("The threshold is {}", THRESHOLD);
    println!("{} is {}", n, if is_big(n) { "big" } else { "small" });

    // Error! Cannot modify a `const`.
    //THRESHOLD = 5;
    // FIXME ^ Comment out this line
}

程序运行结果:

This is Rust
The threshold is 10
16 is big

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-13 10:33:27

边做边学Rust之用户自定义类型的相关文章

Lua-UserData(用户自定义类型)

UserData(用户自定义类型) 意义:使用C语言编写的用于扩展Lua的新类型,方便使用脚本编写或者提高效率 userdata:提供了一块原始的内存区域,用于存储任何东西,在Lua中userdata没有任何预定义操作 生成:void *lua_newuserdata(L,size) 根据指定大小分配一块内存,并将userdata压入栈中,最后返回这个内存块的地址 例子: Lua require "array" a = array.new(1000) print(a); print(a

通过欧拉计划学Rust编程(第54题)

由于研究Libra等数字货币编程技术的需要,学习了一段时间的Rust编程,一不小心刷题上瘾. 刷完欧拉计划中的63道基础题,能学会Rust编程吗? "欧拉计划"的网址: https://projecteuler.net 英文如果不过关,可以到中文翻译的网站: http://pe-cn.github.io/ 这个网站提供了几百道由易到难的数学问题,你可以用任何办法去解决它,当然主要还得靠编程,编程语言不限,论坛里已经有Java.C#.Python.Lisp.Haskell等各种解法,当然

C++的内置类型和用户自定义类型的互相转换

这两种之间的转换主要有两种方式第一就是内置类型转换为用户自定义类型,这里以int类型转换为类类型的对象为例,第二就是类类型转换为int类型 前者依靠转换构造函数,后者依靠自定义的类型转换函数 一.转换构造函数 二.类型转换构造函数 #include <iostream> using namespace std; //转换构造函数只有一个参数,但是有时候这种一个参数的构造函数不仅起到类型转换的作用也起到了构造函数的作用,但是只有一个参数的构造函数才有这种类似的双重身份,并且这种没有拷贝构造的情况

0914,异常语句,类类型(用户自定义类型),分割

异常语句try :尝试 try { //要包括起来的可能有错误的代码 } catch (Exception ex)//抓获错误 { throw ex;  //抛出错误异常 console.writeline ("错误内容"+ex ); } finally { console.write(""); } 类   类型 : class类型 : 用户自定义类型 String :   处理字符串 DateTime : 处理时间 Random :   生产随机数 Math : 

从头开始学JavaScript (十一)——Object类型

原文:从头开始学JavaScript (十一)--Object类型 一.object类型 一个object就是一系列属性的集合,一个属性包含一个名字(属性名)和一个值(属性值). object对于在应用程序中存储和传输数据而言,是非常理想的选择 二.创建object 创建object实例有两种方法: 使用new 操作符后跟object构造函数 使用对象初始化器,也就是对象字面量表示法 2.1使用new 操作符后跟object构造函数创建object实例: 1 var person = new O

怒学Python——第二篇——类型与运算

Python支持5种数据类型,包括数字(numbers).字符串(string).列表(list).元组(tuple)和字典(dictionary).作为一门动态类型语言,不用去声明一个标示符的类型,使用的时候是什么类型会自动判定. 对于定义好的变量,若不使用该变量,可以用del删除来释放占有的资源,如 var = 10 del var Python的数字(numbers):支持int.long.float和complex,比较简单不给出示例. Python的字符串(string):如前面所说的

使用用户自定义类型作为map的key

有时候我们想把用户自定义类型作为std::map的键值.方法一)最简单的方法就是实现该自定义类型的<操作符,代码如下:class Foo{public:    Foo(int num_)        : num(num_)    {    }    bool operator < (const Foo & cmp) const    {        return num < cmp.num;    }      int num;   };之后就可以使用Foo作为map的key

谷歌做了45万次不同类型的文本分类后,总结出一个通用的“模型选择算法”...

谷歌做了45万次不同类型的文本分类后,总结出一个通用的"模型选择算法"... 2018年07月25日 17:43:55 阅读数:6 新智元报道 来源:developers.google.com 编译:肖琴.大明 [导读]谷歌官方推出"文本分类"指南教程.为了最大限度地简化选择文本分类模型的过程,谷歌在进行大约450K的文本分类实验后,总结出一个通用的"模型选择算法",并附上一个完整的流程图,非常实用. 文本分类(Text classificati

思科&新华三&华为边做边学专题,交换路由无线防火墙BGP组播

https://edu.51cto.com/sd/4bbb4 第一阶段: 思科技术阶段 1门课程 36小时21分钟主要介绍网络技术基础知识,思科交换机.思科路由器的配置使用. 第二阶段: 华三技术阶段 3门课程 23小时49分钟主要介绍H3C交换机.H3C路由器.H3C防火墙的配置使用,同时包括高级路由技术BGP专题. 第三阶段: 华为技术阶段 2门课程 6小时20分钟主要介绍华为无线网络的部署(包括AC.AP),另外包括组播专题. 思科&新华三&华为边做边学专题,交换路由无线防火墙BGP