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

原创 2015年11月18日 09:23:15

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


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

相关文章推荐

我学习rust时参考的资料

为方便有兴趣学习rust的同学索引,特意做出这个列表。 rust官方学习文档: 1.http://doc.rust-lang.org/book/README.html (英文) 2.https:...

mac如何升级g++的版本?更改默认gcc版本

本文采用port来安装gcc/g++,然后进行版本切换。

边做边学Rust之Hello World

1. Hello World 这是一个传统Hello World程序的源码: // This is a comment, and will be ignored by the compiler...
  • cnxxrj
  • cnxxrj
  • 2015年11月16日 08:45
  • 1381

边做边学Rust之变量绑定

4 变量绑定 Rust通过静态类型实现类型安全。变量绑定可以在定义时注明类型。然而在大多数情况下,编译器可以从上下文环境中推断出变量类型,大大的减轻了注解的负担。 使用let,可以将值(例...
  • cnxxrj
  • cnxxrj
  • 2015年11月19日 09:22
  • 667

【边做项目边学Android】手机安全卫士06-手机防盗之自定义对话框

修改主界面的titleBar 可以在系统的AndroidManifest.xml文件中修改相应的配置来改变主界面的theme(设置为无titleBar样式)...
  • bruce_6
  • bruce_6
  • 2014年12月29日 10:09
  • 1076

边做游戏边学android—2(飞机大战①创建飞机)

将飞机的素材,放在res/drawable-mdpi文件夹下,创建物品对象的类:package com.example.object;import android.content.res.Resour...

边做边学Python Flask Web开发(5)-- 使用Jinjia2模板(中)

上一篇介绍了Jinjia2模板系统的基本用法,本篇将深入对Jinjia2进行探讨,对网页设计中经常会用到的一些高级特性进行介绍。模板复用复用是网页设计非常常用的特性,比如我们的页面头部的网站名称和页尾...
  • langkew
  • langkew
  • 2016年07月06日 15:41
  • 2802

Python 边做边学 8.2 工具类--配置文件工具(CfgUtil)

搜索使用Python3读取配置文件 CfgUtilpy 代码 confini 代码 简单描述 其他

Grails边做边学入门篇[0]--------讲讲什么是Grails

以前博客里面写过几篇关于Grails的文章,那时我刚刚接触Grails,但是由于个人比较懒,所以没有把那个系列的博客坚持写下来,现在打算重新写一下,毕竟自己接触了一段时间,也有了些真正的体会。在这里介...

边做边学Python Flask Web开发(3)-- Flask Hello World!

由于本系列教程叫做“边做边学”,因此我们在后续的讲解会以实践为主,穿插着介绍基本概念。请大家有条件的话跟着我们一起上机实践,而不要过于纠结深层次的原理,这些我们会在后续的教程中为大家慢慢解释。安装Fl...
  • langkew
  • langkew
  • 2016年06月06日 13:35
  • 1654
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:边做边学Rust之用户自定义类型
举报原因:
原因补充:

(最多只允许输入30个字)