RUST 0x04 Struct

RUST 0x04 Struct

1 定义与实例化(Instantiating)Struct

Struct和tuple很像,因为它们都能存储不同的数据类型。但和tuple不同的是,恁需要命名每一个数据。这样做的好处是,struct比tuple更灵活——不需要依靠数据的顺序就能获取某一个特定的值。

例如:

struct User { // 以下的每一项叫做域(field)
    username: String,
    email: String,
    sign_in_count: u64,
    active: bool,
}

注意中间用的是,而不是;。否则会抛出一个CE。最后一个,可以不写。

为了使用我们创建的这个struct,我们需要为它创建一个实例,并以key: value来赋值。我们不必按和上面相同的顺序来,如:

let user1 = User {
    email: String::from("someone@example.com"),
    username: String::from("someusername123"),
    active: true,
    sign_in_count: 1,
};

如果想从一个struct中得到某个特定的值,我们可以用.。如果实例是可变的,那么我们还可用.对某个特定的域赋值,如:

let mut user1 = User {
    email: String::from("someone@example.com"),
    username: String::from("someusername123"),
    active: true,
    sign_in_count: 1,
};

user1.email = String::from("anotheremail@example.com");

值得注意的是,如果要这样做,那么整个实例必须是可变的,Rust不允许只有某几个域是可变的。

我们也可以手写一个初始化函数,如:

fn build_user(email: String, username: String) -> User {
    User {
        email: email,
        username: username,
        active: true,
        sign_in_count: 1,
    }
}

运用简写域初始化(Field Init Shorthand)

为了方便,我们可以用field init shorthand来重写上面的函数:

fn build_user(email: String, username: String) -> User {
    User {
        email,
        username,
        active: true,
        sign_in_count: 1,
    }
}

我们想使email: email,,因为它们两者有着同样的名称,所以我们可以直接简写为email,

运用Struct Update Syntax从其他实例创建实例

如果要创建一个很多值都和一个旧的实例相同的实例,我们可以使用struct update syntax

首先,是不用update syntax的方法:

let user2 = User {
    email: String::from("another@example.com"),
    username: String::from("anotherusername567"),
    active: user1.active,
    sign_in_count: user1.sign_in_count,
};

用update syntax..,可以以更少的代码实现相同的效果:

let user2 = User {
    email: String::from("another@example.com"),
    username: String::from("anotherusername567"),
    ..user1
};
  • .. → 剩下的其它域的值将会与给定的实例相同。

Using Tuple Structs without Named Fields to Create Different Types

我们也可以定义长得很像tuple的struct——tuple struct。如:

struct Color(i32, i32, i32);
struct Point(i32, i32, i32);

let black = Color(0, 0, 0);
let origin = Point(0, 0, 0);

Unit-Like Structs Without Any Fields

unit-like struct没有任何域,日后再说。

2 Method Syntax

Method和function很像:它们都是用fn声明,且都能有参数和返回值。但是method是在struct(或enum等)里定义的,且第一个参数是self

定义Method

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

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

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

    println!(
        "The area of the rectangle is {} square pixels.",
        rect1.area()
    );
}
  • impl → implementation
  • self → self (记得加&(虽然在这个程序里不加也可以))
  • . → call Method Syntax

含更多参数的Method

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

    fn can_hold(&self, other: &Rectangle) -> bool {
        self.width > other.width && self.height > other.height
    }
}

Associated Functions

associated function就是写在impl里却又不用self做参数的函数。它们是函数,而不是method。比如String::from

associated function经常用来写构造函数,如:

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

要调用它,我们需要用::,比如 let sq = Rectangle::square(3);

Mutiple impl Blocks

每个struct都可以有多个impl语句块,如:

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

impl Rectangle {
    fn can_hold(&self, other: &Rectangle) -> bool {
        self.width > other.width && self.height > other.height
    }
}

小结

  • struct可以用来创建传统类型,将相关的数据存在一起并命名。

  • method可以用来对struct的实例进行操作。

  • associated function可以用来创建namespace里的function。

参考

The Rust Programming Language by Steve Klabnik and Carol Nichols, with contributions from the Rust Community : https://doc.rust-lang.org/book/

上一篇:配置nginx负载均衡


下一篇:WPF 的 VisualBrush 只刷新显示的视觉效果,不刷新布局范围