Rust学习:通过例子学Rust

文章目录

Rust官方练习:通过例子学Rust

1. Hello World

1.1 注释

    // 使用 // 进行单行注释
    //

    // 也可以使用 /* */ 来进行块注释
    /* */  
    
    // 使用 /// 来进行文档注释
    /// 

1.2 格式化输出

fn main() {
   
    // format! 返回一个字符串 String类型的变量
    let name = vec!["Peter", "Trunph", "James"];

    // 并且,我们可以使用位置参数来进行格式化输出
    // 这将所有的后续输出数据当作一个数组使用
    // 如下例,将name[0], name[1], name[2] 视为一个数组
    // 则 {0} 表示这个数组的索引 0 的值,也就是 name[0]
    // 当然 {}内也可以不指定索引,则其默认从 0 开始,并且递增
    let str1 = format!("{0}-{1}-{2}", name[0], name[1], name[2]);
    let str2 = format!("{}-{}-{}", name[0], name[1], name[2]);
    println!("{}", str1);
    println!("{}", str2);
    println!("****************************");

    // 并且, format还可以传递同作用域的变量
    // 如果在其参数列表中存在相同名字的数据,则优先使用参数列表
    let people = "Rustaceans";
    let disv1 = format!("Hello {people}!");
    let disv2 = format!("Hello {people}!", people = "Killer");
    println!("{}", disv1);
    println!("{}", disv2);
    println!("****************************");

    // println! 将文本输出到终端( print!和其作用相同,只不过该宏不进行换行)
    print!("我不换行了--");
    println!("我得换个行--");
    println!("****************************");

    // 我们在 format说明时使用了位置参数进行数据的传递
    // 除了位置参数,还可以使用命名参数
    println!(
        "{subject} {verb} {object}",
        object = "the lazy dog",
        subject = "the quick brown fox",
        verb = "jumps over"
    );
    println!("****************************");

    // 那么如何进行其他格式化的输出呢,比如进制转换,对齐,保留小数点等
    // 可以在 `:` 后面指定特殊的格式。
    // {:b} 表示把传入的数据转换为二进制输出,看下面这个栗子
    // 它把 2 转换为二进制 10 进行输出
    println!("{} of {:b} people know binary, the other half don't", 1, 2);
    println!("****************************");

    // 你可以按指定宽度来右对齐文本。
    // 下面语句输出 "     1",5 个空格后面连着 1。
    // 同理,你也可以左对齐文本
    println!("{number:<width$}", number = 1, width = 6);
    println!("{number:>width$}", number = 1, width = 6);
    println!("****************************");
    // 并且你可以使用符号 0 来让 0 占有空位置
    // 注意这是在左边补 0 ,和左对齐右对齐无关
    println!("{number:>0width$}", number = 1, width = 6);
    println!("{number:<0width$}", number = 1, width = 6);
    println!("****************************");
    // 更简便的,你可以不使用命名参数,直接使用如下方式
    // 这表示共计占有 4 位宽度,左边用 0 补齐
    println!("{:04}", 5);
    println!("****************************");

    // 保留特定位小数点
    let pi = 3.141592;
    // 我们想让 pi 保留三位小数点输出
    // 方式如下:冒号前面的是位置参数,他代表参数中的索引 0
    // 冒号后面我们使用一个 . ,再加上要保留的位数即可
    // {0:.3} 表示保留三位小数点
    println!("Pi is roughly {0:.3}", pi);
    println!("****************************");

    // 还有另外一种使用位置参数来定义位数的
    // 这代表使用参数索引 1 的值来作为宽度
    // 并且,默认的数据索引可以省略不写
    println!("{:1$}", 0, 2);
    println!("****************************");
    // 使用命名参数的表示方法同理
    println!("{:>width$}", 10, width = 6);
    println!("****************************");

    // 最后我们看一下本节的习题
    // 用一个 println! 宏,通过控制显示的小数位数来打印:Pi is roughly 3.142
    //(Pi 约等于 3.142)。为了达到练习目的,使用 let pi = 3.141592 作为 Pi 的近似值
    // 其实我们在上面已经实现了,不妨再做一遍加深印象
    let pi = 3.141592;
    println!("Pi is roughly {0:.3}", pi);

    // 本节练习地址
    // https://rustwiki.org/zh-CN/rust-by-example/hello/print.html

    // 出去上述说明的格式化方式,还有许多其他的格式化方式
    // 如输出 0x55这种十六进制格式的方式等等,以及重要的 debug方式
    // 可以到下面的官方标准库网站进行查阅
    // https://rustwiki.org/zh-CN/std/fmt/
}
1.2.1 调试(Debug)
#[derive(Debug)]
enum Gender {
   
    Male,
    Female,
}

#[derive(Debug)]
struct Student {
   
    grade: f64,
    height: u32,
    gender: Gender,
    hobby: String,
}

fn main() {
   
    // 并不是所有的类型都能够使用std::fmt的格式进行打印
    // 想要能够进行这样的打印,需要实现一个可以打印的 trait
    // 那么我们该如何输出那些不能进行 fmt::Display的类型呢
    // 答案就是使用fmt::Debug进行实现
    // 我们需要导入一个 Attribute,就是 derive 这个属性
    // 他会对标签进行自动的推导
    // 我们在程序外部导入 derive 对 fmt::Debug 进行自动推导
    // 然后我们定义一个结构体 Student,并且进行实例化
    let peter = Student {
   
        grade: 95.0,
        height: 175,
        gender: Gender::Male,
        hobby: String::from("Play LOL"),
    };

    let jane = Student {
   
        grade: 94.5,
        height: 165,
        gender: Gender::Female,
        hobby: String::from("Reading"),
    };

    // 下面我们使用 printt!宏来打印 这两个实例
    // 我们会发现他并不能进行打印,因为他没有实现 Display
    // println!("{}, {}", peter, jane);

    // 下面我们使用 Debug的方式进行打印
    println!("{:#?}\n{:#?}", peter, jane);
    // 输出信息如下
    /*
        Student {
            grade: 95.0,
            height: 175,
            gender: Male,
            hobby: "Play LOL",
        }
        Student {
            grade: 94.5,
            height: 165,
            gender: Female,
            hobby: "Reading",
        }
     */ 
}
1.2.2 显示(Display)
use std::fmt;

#[derive(Debug)]
enum Gender {
   
    Male,
    Female,
}

// 为 Gender实现一个方法,这个方法可以被调用返回他的字符串切片
impl Gender {
   
    fn get_str(&self) -> &str {
   
        match *self {
   
            Gender::Male => "Male",
            Gender::Female => "Female",
        }
    }
}

#[derive(Debug)]
struct Student {
   
    grade: f64,
    height: u32,
    gender: Gender,
    hobby: String,
}

// 为 Student实现 Display
impl fmt::Display for Student {
   
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
   
        write!(
            f,
            "grade is {}, height is {}, gender is {}, hobby is {}",
            self.grade,
            self.height,
            self.gender.get_str(),
            self.hobby
        )
    }
}

// 习题练习
#[derive(Debug)]
struct Point2D {
   
    x: f64,
    y: f64,
}

// 对 `Point2D` 实现 `Display`
impl fmt::Display for Point2D {
   
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
   
        // 自定义格式,使得仅显示 `x` 和 `y` 的值。
        write!(f, "{} + {}i", self.x, self.y)
    }
}

fn main() {
   
    // 在 1.2.1 中,我们使用 derive 属性对 Debug 进行推导进行打印
    // 但是它不够简洁,我们可以自己来实现 fmt::Display方法
    // 首先引入fmt模块
    // 然后我们把上个例子的结构体拿过来
    // 之后,我们为 struct和 enum实现 Display这个 trait
    // 见上方的实现
    // 定义完成后,我们来打印一下
    let peter = Student {
   
        grade: 95.0,
        height: 175,
        gender: Gender::Male,
        hobby: String::from("Play LOL"),
    };

    let jane = Student {
   
        grade: 94.5,
        height: 165,
        gender: Gender::Female,
        hobby: String::from("Reading"),
    };

    println!("{}", peter);
    println!("{}", jane);
    println!("{:#?}", peter);
    println!("{:#?}", jane);

    // 打印结果如下,可见,我们成功为struct实现了Display这个trait
    /*
       grade is 95, height is 175, gender is Male, hobby is Play LOL
       grade is 94.5, height is 165, gender is Female, hobby is Reading
       Student {
           grade: 95.0,
           height: 175,
           gender: Male,
           hobby: "Play LOL",
       }
       Student {
           grade: 94.5,
           height: 165,
           gender: Female,
           hobby: "Reading",
       }
    */
    // 可以看到,我们自己实现的Display和 Debug的输出方式明显不同

    // 最后我们来看一下这一节的习题
    let point = Point2D {
    x: 3.3, y: 7.2 };
    // 使用我们定义的 Display打印
    println!("{}", point);
    // 使用Debug打印
    println!("{:#?}", point);
    // 输出结果如下,目标完成
    /*
        3.3 + 7.2i
        Point2D {
            x: 3.3,
            y: 7.2,
        }
    */
}
1.2.3 测试实例:List
use ::std::fmt;

// 定义一个元组结构体
struct List(Vec<i32>);

// 为其实现Display这个trait
// impl fmt::Display for List {
   
//     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
   
//         let vec = &self.0;
//         write!(f, "[")?;
//         for (count, item) in vec.iter().enumerate() {
   
//             if count != 0 {
   
//                 write!(f, ", ")?;
//             }
//             write!(f, "{}", item)?;
//         }
//         write!(f, "]")
//     }
// }

impl fmt::Display for List {
   
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
   
        let vec = &self.0;
        write!(f, "[")?;
        for (count, item) in vec.iter().enumerate() {
   
            if count != 0 {
   
                write!(f, ", ")?;
            }
            write!(f, "{}: {}", count, item)?;
        }
        write!(f, "]")
    }
}

fn main() {
   
    // 这节来学习一下 ?符号的使用
    // ? 操作符会自动进行match匹配,如果错误则会返回,没有错误则继续
    let v = List(vec![1, 2, 3]);
    println!("{}", v);
    // 输出如下
    // [1, 2, 3]
    // 可见,使用 ? 可以省略我们很多的重复语句

    // 下面我们来看一下本节的习题

    //更改程序使 vector 里面每个元素的下标也能够打印出来。新的结果如下:
    //[0: 1, 1: 2, 2: 3]

    // 我们先将之前的注释掉
    // 改完之后,输出一下试试
    println!("{}", v);
    // 结果如下
    // [0: 1, 1: 2, 2: 3]
    // 目标达成
}
1.2.4 格式化
use std::fmt::{
   self, Display};

// 定义一个结构体
struct City {
   
    name: &'static str,
    lat: f32,
    lon: f32,
}

struct Color {
   
    red: u8,
    green: u8,
    blue: u8,
}

// 为City实现Display
impl Display for City {
   
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
   
        let lac_c = if self.lat > 0.0 {
    'N' } else {
    'S' };
        let lon_c = if self.lon > 0.0 {
    'E' } else {
    'W' };

        write!(
            f,
            "{}: {:3}°{} {:3}°{}",
            self.name,
            self.lat.abs(),
            lac_c,
            self.lon.abs(),
            lon_c
        )
    }
}

// 习题:为Color实现Display
impl Display for Color {
   
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
   
        write!(
            f,
            "RGB ({0}, {1}, {2}) 0x{0:02X}{1:02X}{2:02X}",
            self.red, self.green, self.blue
        )
    }
}

fn main() {
   
    // 之前我们介绍format!等宏时说到
    // 在 {} 中加入 :param 可以改变输出的格式
    // 这个功能是使用 trait来实现的
    // 下面我们来自己实现一下这个trait
    for city in [
        City {
   
            name: "Dublin",
            lat: 53.347778,
            lon: -6.259722,
        },
        City {
   
            name: "Oslo",
            lat: 59.95,
            lon: 10.75,
        },
        City {
   
            name: "Vancouver",
            lat: 49.25,
            lon: -123.1,
        },
    ]
    .iter()
    {
   
        println!("{}", *city);
    }
    // 输出结果如下
    // Dublin: 53.34778°N 6.259722°W
    // Oslo: 59.95°N 10.75°E
    // Vancouver: 49.25°N 123.1°W

    // 下面我们来看一下本节习题
    // 为上面的 Color 结构体实现 fmt::Display,应得到如下的输出结果:
    // RGB (128, 255, 90) 0x80FF5A
    // RGB (0, 3, 254) 0x0003FE
    // RGB (0, 0, 0) 0x000000
    for color in [
        Color {
   
            red: 128,
            green: 255,
            blue: 90,
        },
        Color {
   
            red: 0,
            green: 3,
            blue: 254,
        },
        Color {
   
            red: 0,
            green: 0,
            blue: 0,
        },
    ]
    .iter()
    {
   
        // 在添加了针对 fmt::Display 的实现后,请改用 {} 检验效果。
        println!("{}", *color)
    }

    // 结果如下
    /*
        RGB (128, 255, 90) 0x80FF5A
        RGB (0, 3, 254) 0x0003FE
        RGB (0, 0, 0) 0x000000
    */
    // 任务完成

    // 虽然我们任务完成了,但是离我们开头说的实现{:param}这种实现形式
    // 还是差了很多,那么我们怎么实现这种格式的输出呢
    // 首先我们定义一个结构体,它表示一个浮点数 x.y
    // x是他的整数部分,y是他的小数部分,并且我们要求它能够实现
    // {:param}可以指定它小数输出部分的位数
    // 下面我们来实现它
    let flo = Flo {
    x: 18, y: 52 };
    println!("{:10.04}", flo);
    // 我们要求是将flo结构体中的x作为整数,y作为小数
    // 合并成一个数进行输出,并且可以指定小数的位数
    // 上述例子将会输出   18.5200
    // 示例成功
    // 读者如果想要实现其他不同的功能与输出方式
    // 请阅读 https://rustwiki.org/zh-CN/std/fmt/#formatting-traits
    // 来寻找自己想要的方法,博主才疏学浅,就不过多说明了
}

struct Flo {
   
    x: i32,
    y: u32,
}

impl fmt::Display for Flo {
   
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
   
        let num: f64 = format!("{}.{}", self.x, self.y).parse().unwrap();
        let decimals = f.precision().unwrap_or(3);
        let string = format!("{:.*}", decimals, num);
        f.pad_integral(true, "", &string)
    }
}

2. 原生类型

fn main() {
   
    // Rust中的那些原生类型
    // 标量类型
    // 有符号整数
    let itype1: i8 = 8;
    let itype2: i16 = 16;
    let itype3: i32 = 32;
    let itype4: i64 = 64;
    let itype5: i128 = 128;
    let itype6: isize = 64; // 指针宽度,32位或64位

    // 无符号整数
    let utype1: u8 = 8;
    let utype2: u16 = 16;
    let utype3: u32 = 32;
    let utype4: u64 = 64;
    let utype5: u128 = 128;
    let utype6: usize = 64; // 指针宽度,32位或64位

    // 也可以使用后缀声明变量类型
    let utype_suffix = 50i32;

    // 浮点数
    let ftype1: f32 = 32.00;
    let ftype2: f64 = 64.00;

    // 布尔型
    let bool_type: bool = true; // true or false

    // 单元类型:空元组
    let unit_type = ();

    // 复合类型
    // 数组
    let array_type = [1, 2, 3, 4, 5];

    // 元组
    let tuple_type = (1, 2, 3, 4, 5);

    // 定义一个变量时,如果不显示声明变量的可变性,则变量默认不可变
    // 使用mut来使变量可变
    let mut mutable = 56;

    // 变量的值可以改变,但是变量的类型不能改变
    // 但是你可以使用shadow来遮蔽前面的变量
    // mutable = true;
    let mutable = true;
}

2.1 字面量和运算符

fn main() {
   
    // 整数相加
    println!("1 + 2 = {}", 1u32 + 2);

    // 整数相减
    println!("1 - 2 = {}", 1i32 - 2);
    // 试一试 ^ 尝试将 `1i32` 改为 `1u32`,体会为什么类型声明这么重要

    // 短路求值的布尔逻辑
    println!("true AND false is {}", true && false);
    println!("true OR false is {}", true || false);
    println!("NOT true is {}", !true);

    // 位运算
    println!("0011 AND 0101 is {:04b}", 0b0011u32 & 0b0101);
    println!("0011 OR 0101 is {:04b}", 0b0011u32 | 0b0101);
    println!("0011 XOR 0101 is {:04b}", 0b0011u32 ^ 0b0101);
    println!("1 << 5 is {}", 1u32 << 5);
    println!("0x80 >> 2 is 0x{:x}", 0x80u32 >> 2);

    // 使用下划线改善数字的可读性!
    println!("One million is written as {}", 1_000_000u32);
}

2.2 元组

use std::fmt;

// 元组可以充当函数的参数和返回值
fn reverse(pair: (i32, bool)) -> (bool, i32) {
   
    // 可以使用 `let` 把一个元组的成员绑定到一些变量
    let (integer, boolean) = pair;
    (boolean, integer)
}

// 在练习中要用到下面这个结构体。
#[derive(Debug)]
struct Matrix(f32, f32, f32, f32);

fn main() {
   
    // 包含各种不同类型的元组
    let long_tuple = (1u8, 2u16, 3u32, 4u64,
                      -1i8, -2i16, -3i32, -4i64,
                      0.1f32, 0.2f64,
                      'a', true);

    // 通过元组的下标来访问具体的值
    println!("long tuple first value: {}", long_tuple.0);
    println!("long tuple second value: {}", long_tuple.1);

    // 元组也可以充当元组的元素
    let tuple_of_tuples = ((1u8, 2u16, 2u32), (4u64, -1i8), -2i16);

    // 元组可以打印
    println!("tuple of tuples: {:?}", tuple_of_tuples);

    // 但很长的元组无法打印
    // let too_long_tuple = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13);
    // println!("too long tuple: {:?}", too_long_tuple);
    // 原因是并没有实现Debug这个Trait

    let pair = (1, true);
    println!("pair is {:?}", pair);

    println!("the reversed pair is {:?}", reverse(pair));

    // 创建单元素元组需要一个额外的逗号,这是为了和被括号包含的字面量作区分。
    println!("one element tuple: {:?}", (5u32,));
    println!("just an integer: {:?}", (5u32));

    // 元组可以被解构(deconstruct),从而将值绑定给变量
    let tuple = (1, "hello"
  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值