zl程序教程

您现在的位置是:首页 >  其它

当前栏目

rustlings练习III–struct、enum

练习 struct Enum III rustlings
2023-06-13 09:15:43 时间

rustlings练习III–struct、enum

于2022年10月17日2022年10月17日由Sukuna发布

6-1

这一题我们要了解最基础的结构体、元组型结构体以及单元结构体的定义和初始化.

定义的方法两者有所不同,一个是用{}扩起来,不同的元素之间用逗号隔开,还有就是元组型,用()扩起来,不同的元素用逗号隔开.访问的方式一个是结构体.名字和结构体.顺序

// structs1.rs
// Address all the TODOs to make the tests pass!
// Execute `rustlings hint structs1` or use the `hint` watch subcommand for a hint.

struct ColorClassicStruct {
    red : i32,
    blue : i32,
    green : i32,
}

struct ColorTupleStruct(i32,i32,i32);

#[derive(Debug)]
struct UnitLikeStruct;

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn classic_c_structs() {
        // TODO: Instantiate a classic c struct!
        let green = ColorClassicStruct{
            red:0,
            green:255,
            blue:0,
        };

        assert_eq!(green.red, 0);
        assert_eq!(green.green, 255);
        assert_eq!(green.blue, 0);
    }

    #[test]
    fn tuple_structs() {
        // TODO: Instantiate a tuple struct!
        let green = ColorTupleStruct(0, 255, 0);

        assert_eq!(green.0, 0);
        assert_eq!(green.1, 255);
        assert_eq!(green.2, 0);
    }

    #[test]
    fn unit_structs() {
        // TODO: Instantiate a unit-like struct!
        let unit_like_struct = UnitLikeStruct{};
        let message = format!("{:?}s are fun!", unit_like_struct);

        assert_eq!(message, "UnitLikeStructs are fun!");
    }
}

6-2

这一题我们需要用一个已经定义好的结构体来声明一个结构体,有一种朴素的方法是,使用A : others.A来定义,还有就是先定义有不同的,再使用..other定义相同的属性.

// structs2.rs
// Address all the TODOs to make the tests pass!
// Execute `rustlings hint structs2` or use the `hint` watch subcommand for a hint.

#[derive(Debug)]
struct Order {
    name: String,
    year: u32,
    made_by_phone: bool,
    made_by_mobile: bool,
    made_by_email: bool,
    item_number: u32,
    count: u32,
}

fn create_order_template() -> Order {
    Order {
        name: String::from("Bob"),
        year: 2019,
        made_by_phone: false,
        made_by_mobile: false,
        made_by_email: true,
        item_number: 123,
        count: 0,
    }
}


#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn your_order() {
        let order_template = create_order_template();
        // TODO: Create your own order using the update syntax and template above!
        let your_order = Order{
            name : String::from("Hacker in Rust"),
            count : 1,
            ..order_template
        };
        assert_eq!(your_order.name, "Hacker in Rust");
        assert_eq!(your_order.year, order_template.year);
        assert_eq!(your_order.made_by_phone, order_template.made_by_phone);
        assert_eq!(your_order.made_by_mobile, order_template.made_by_mobile);
        assert_eq!(your_order.made_by_email, order_template.made_by_email);
        assert_eq!(your_order.item_number, order_template.item_number);
        assert_eq!(your_order.count, 1);
    }
}

6-3

这一题我们需要完成Package的impl块

    fn is_international(&self) -> ??? {
        // Something goes here...
    }

    fn get_fees(&self, cents_per_gram: i32) -> ??? {
        // Something goes here...
    }

函数都很好写,然后可以这样调用:Package::get_fees来调用impl的方法

impl Package {
    fn new(sender_country: String, recipient_country: String, weight_in_grams: i32) -> Package {
        if weight_in_grams <= 0 {
            panic!("Can not ship a weightless package.")
        } else {
            Package {
                sender_country,
                recipient_country,
                weight_in_grams,
            }
        }
    }

    fn is_international(&self) -> bool {
        if self.sender_country == self.recipient_country{
            false
        }
        else{
            true
        }
    }

    fn get_fees(&self, cents_per_gram: i32) -> i32 {
        self.weight_in_grams * cents_per_gram
    }
}

比如说Package::new()就可以生成一个新的Package块

对于impl块的调用,我们给出了两种形式,一种是类::方法,一种是实例.方法

fn create_international_package() {
        let sender_country = String::from("Spain");
        let recipient_country = String::from("Russia");

        let package = Package::new(sender_country, recipient_country, 1200);

        assert!(package.is_international());
    }

7-1

这一个我们仅需要声明一个枚举类型即可,声明的方法就是enum 名字{},{}内内容用枚举括起来.

// enums1.rs
// No hints this time! ;)

#[derive(Debug)]
enum Message {
    // TODO: define a few types of messages as used below
    Quit,
    Echo,
    Move,
    ChangeColor,
}

fn main() {
    println!("{:?}", Message::Quit);
    println!("{:?}", Message::Echo);
    println!("{:?}", Message::Move);
    println!("{:?}", Message::ChangeColor);
}

7-2

这次的声明需要我们像书上说的那样,让枚举变量的每一个枚举值和一个结构体匹配.可能不仅仅是一个结构体,有可能是一个元组或者仅仅是一个值.

// enums2.rs
// Execute `rustlings hint enums2` or use the `hint` watch subcommand for a hint.

// I AM NOT DONE

#[derive(Debug)]
enum Message {
    Move{x : i32, y : i32},
    Echo(String),
    ChangeColor(i32,i32,i32),
    Quit,
}

impl Message {
    fn call(&self) {
        println!("{:?}", &self);
    }
}

fn main() {
    let messages = [
        Message::Move { x: 10, y: 30 },
        Message::Echo(String::from("hello world")),
        Message::ChangeColor(200, 255, 255),
        Message::Quit,
    ];

    for message in &messages {
        message.call();
    }
}

这种特性很好记忆,只需要把枚举值当成一种结构体的类型就好了.

7-3 这一题可能会有点难,我们需要根据我们已经写好的枚举类型特出特定的匹配执行特定的操作,匹配的格式是match 表达式{},{}里面是 表达式 => 做什么、返回什么

// enums3.rs
// Address all the TODOs to make the tests pass!
// Execute `rustlings hint enums3` or use the `hint` watch subcommand for a hint.

// I AM NOT DONE

enum Message {
    Move(Point),
    Echo(String),
    ChangeColor((u8,u8,u8)),
    Quit,
}

struct Point {
    x: u8,
    y: u8,
}

struct State {
    color: (u8, u8, u8),
    position: Point,
    quit: bool,
}

impl State {
    fn change_color(&mut self, color: (u8, u8, u8)) {
        self.color = color;
    }

    fn quit(&mut self) {
        self.quit = true;
    }

    fn echo(&self, s: String) {
        println!("{}", s);
    }

    fn move_position(&mut self, p: Point) {
        self.position = p;
    }

    fn process(&mut self, message: Message) {
        match message{
            Message::Move(point) => {
                State::move_position(self,point);
            },
            Message::Quit => {
                State::quit(self);
            },
            Message::ChangeColor(color) => {
                State::change_color(self,color);
            }
            Message::Echo(mes) => {
                State::echo(self,mes);
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_match_message_call() {
        let mut state = State {
            quit: false,
            position: Point { x: 0, y: 0 },
            color: (0, 0, 0),
        };
        state.process(Message::ChangeColor((255, 0, 255)));
        state.process(Message::Echo(String::from("hello world")));
        state.process(Message::Move(Point { x: 10, y: 15 }));
        state.process(Message::Quit);

        assert_eq!(state.color, (255, 0, 255));
        assert_eq!(state.position.x, 10);
        assert_eq!(state.position.y, 15);
        assert_eq!(state.quit, true);
    }
}

注意有一点,再引用枚举类型的时候别忘记加::来规定,Message::Move和Move是不一样的,别忘了加Message::Move.

8-1

这一题需要我们把这个模块里面的某个函数隐藏起来

mod sausage_factory {
    // Don't let anybody outside of this module see this!
    fn get_secret_recipe() -> String {
        String::from("Ginger")
    }

    fn make_sausage() {
        get_secret_recipe();
        println!("sausage!");
    }
}

fn main() {
    sausage_factory::make_sausage();
}

其实这个很简单,因为在一个模块中,模块里面的任何一个元素都是隐藏的,或者说私有的,在前面加上一个pub就是.

8-2

这一题需要我们使用use来将一些模块添加到我们的“相对变量环境”中,如同Linux的PATH一样.

还需要我们了解as的用法.

mod delicious_snacks {
    // TODO: Fix these use statements
    pub use self::fruits::PEAR as fruit;
    pub use self::veggies::CUCUMBER as veggie;

    mod fruits {
        pub const PEAR: &'static str = "Pear";
        pub const APPLE: &'static str = "Apple";
    }

    mod veggies {
        pub const CUCUMBER: &'static str = "Cucumber";
        pub const CARROT: &'static str = "Carrot";
    }
}

当然,还有一点就是,如果use前面加了个pub,就是说所有的模块都能使用这个use的结果,如果没加pub,代表仅限delicious_snacks这个模块能使用这个use的结果.

8-3

这一题需要我们use std里面的库,这里我使用glob运算混过去了

// TODO: Complete this use statement
use std::time::*;

fn main() {
    match SystemTime::now().duration_since(UNIX_EPOCH) {
        Ok(n) => println!("1970-01-01 00:00:00 UTC was {} seconds ago!", n.as_secs()),
        Err(_) => panic!("SystemTime before UNIX EPOCH!"),
    }
}