• Rust 常见集合


      Rust标准库中包含一系列标量的数据结构被称为集合,大部分其他的数据结构类型都代表一个特定的值,不过集合可以包含多个值,不同于内建的数组和元组类型,这些集合指向的数据是存储在堆上的,这意味着数据的数量不必在编译时已知,并且还可以随着程序的运行增长或缩小,每种集合都有着不同的功能和成本,而根据当前情况选择合适的集合,这是一种本事。

      下面我们要介绍的广泛使用的集合:

        1、vector:允许我们一个挨着一个的存储一系列数量可变的值

        2、string:字符串是字符的集合

        3、哈希map:允许我们将值与一个特定的键相关联,文档:https://doc.rust-lang.org/stable/std/collections/

    vector 用来储存一系列的值
      我们要讲到的第一个类型是 Vec<T> ,也被称为 vector。vector 允许我们在一个单独的数据结构中储存多于一个的值,它在内存中彼此相邻地排列所有的值。vector 只能储存相同类型的值。它们在拥有一系列项的场景下非常实用,例如文件中的文本行或是购物车中商品的价格。
    fn main() {
        // 原始的创建vector方式
        let v: Vec<i32> = Vec::new(); // 这里使用了<T> 来进行类型注释,来约束v要存储的类型
        
        // 自带类型推导,且使用Rust提供的宏vec!来取代Vec::new()
        let v1 = vec![1,2,3];
    
        println!("v:{:?},v1:{:?}",v,v1);  //v:[],v1[1, 2, 3]
    
        // 更新vector
        let mut v = vec![];   // vec! 相当于 Vec::new(), Rust后面会自动判断类型
        v.push(1);
        // v.push("we");  // 报错,类型不一致
        v.push(4);  // 使用 push 方法向 vector 增加值
    
        println!("v:{:?}",v);  // v:[1, 4]
    
        //  丢弃 vector 时也会丢弃其所有元素,当 vector 被丢弃时,所有其内容也会被丢弃,这意味着这里它包含的整数将被清理
    }
    

      这里 v 离开作用域并被丢弃,当 vector 被丢弃时,所有其内容也会被丢弃,这意味着这里它包含的整数将被清理。这可能看起来非常直观,不过一旦开始使用 vector 元素的引用,情况就变得有些复杂了。

    读取vector的元素

      有两种方法引用 vector 中储存的值。为了更加清楚的说明这个例子,我们标注这些函数返回的值的类型。

    fn main() {
       let v = vec![1,2,3,4,5];
    
       let third: &i32 = &v[2];  // 使用 & 和 [] 返回一个引用
       println!("The third element is {}",third);
    
       match v.get(2) {  // get方式获取会返回一个Option<&T>
           Some(third) => println!("the third element is {}",third),
           None => println!("there is no third element"),
       }
    
       println!("索引获取: {}",&v[3]);  // 索引获取: 4,这种方式如果越界会panic
       println!("get获取: {:?}",v.get(3)); // get获取: Some(4),配合match更加安全,因为有None判断
    }
    

      注意,一旦程序获取了一个有效的引用,借用检查器将会执行所有权和借用规则(第四章讲到)来确保 vector 内容的这个引用和任何其他引用保持有效。回忆一下不能在相同作用域中同时存在可变和不可变引用的规则:

    fn main() {
       let mut v = vec![1,2,3,4,5];
       let first = &v[0];
    
       v.push(6);  // 报错,因为此时v有一个引用&v[0],但是这里进行了push动作,
       // 要求v的内存要重新分配,但是又存在引用,所以不行
       println!("the first element is:{}",first);
    }
    

      在 vector 的结尾增加新元素时,在没有足够空间将所有所有元素依次相邻存放的情况下,可能会要求分配新内存并将老的元素拷贝到新的空间中。这时,第一个元素的引用就指向了被释放的内存。借用规则阻止程序陷入这种状况。

    遍历vector元素

      无需通过索引一次一个的访问,可以使用for循环来获取i32的vecotr的每个元素的不可变引用并打印:

    fn main() {
       let v = vec![1,2,3,4,5];
    
       // 遍历不可变引用来读取
       for i in &v {
           println!{"{}",i};
       }
    
       // 遍历可变引用来修改
       let mut v = vec![4,4,2,2,9];  // 首先元素是可变的mut
       for i in &mut v {   // 其次引用是可变的
           *i += 50;  // 最后作用的是需要使用*
       }
       println!("change v: {:?}",v);
    }
    

      

    使用枚举来存储多种类型

      我们提到 vector 只能储存相同类型的值,这是很不方便的,因为我们需要存储一系列不同类型的值的用例,幸运的是枚举的成员都被定义为相同的枚举类型,所以当需要在vector中存储不同类型的值时,我们可以给其中的值套成外壳(枚举)。

      假如我们想要从电子表格的一行中获取值,而这一行的有些列包含数字,有些包含浮点值,还有些是字符串。我们可以定义一个枚举,其成员会存放这些不同类型的值,同时所有这些枚举成员都会被当作相同类型,那个枚举的类型。接着可以创建一个储存枚举值的vector,这样最终就能够储存不同类型的值了。

    #[derive(Debug)]
    enum Spreadsheet {
        Int(i32),
        Float(f64),
        Text(String),
    }
    
    fn main() {
        let row = vec![
            Spreadsheet::Int(3),
            Spreadsheet::Text(String::from("wanglx")),
            Spreadsheet::Float(1.12),
        ];
        println!("{:?}",row);  // [Int(3), Text("wanglx"), Float(1.12)]
    }
    

      Rust 在编译时就必须准确的知道 vector 中类型的原因在于它需要知道储存每个元素到底需要多少内存。第二个好处是可以准确的知道这个 vector 中允许什么类型。如果 Rust 允许 vector存放任意类型,那么当对 vector 元素执行操作时一个或多个类型的值就有可能会造成错误。

      请一定去看看标准库中 Vec 定义的很多其他实用方法的 API 文档。例如,除了 push 之外还有一个 pop 方法,它会移除并返回vector 的最后一个元素。

     
    字符串
      Rust 的核心语言中只有一种字符串类型: str ,字符串 slice,它通常以被借用的形式出现, &str 。第四章讲到了 字符串 slice:它们是一些储存在别处的 UTF-8 编码字符串数据的引用。比如字符串字面值被储存在程序的二进制输出中,字符串 slice 也是如此。称作 String 的类型是由标准库提供的,而没有写进核心语言部分,它是可增长的、可变的、有所有权的、UTF-8 编码的字符串类型。当 Rustacean 们谈到 Rust 的 “字符串”时,它们通常指的是 String 和字符串 slice &str 类型,而不仅仅是其中之一。虽然本部分内容大多是关于 String 的,不过这两个类型在 Rust 标准库中都被广泛使用, String 和字符串slice 都是 UTF-8 编码的。
    fn main() {
        // 新建一个字符串
        let mut s = String::new();
    
        s = "initial contents".to_string();  // 使用to_string()将&str转换为String
    
        let s = "initial contents".to_string();
    
        let s = String::from("initial contents");  // 等价于上面,使用String::From
    
        println!("s:{}",s);
    
        // 字符串的更新
        let mut s = String::from("foo");
        s.push_str("bar");  //  push_str 方法采用字符串 slice,因为我们并 不需要获取参数的所有权
        println!("push_str:{}",s);  // foobar
    
        let mut s1 = String::from("foo ");
        let s2 = "bar";
        s1.push_str(s2); // 这说明只是引用没有获取所有权
    
        println!("s2:{},s1:{}",s2,s1); // s2:bar,s1:foo bar
    
        let mut s4 = String::from("Foo ");
        s4.push('x');  // push 可以添加一个字符
        println!("s4:{}",s4);
    
        // + 和 format
        let s5 = String::from("Hello ");
        let s6 = String::from("Everyone");
        let s7 = s5 + &s6;  //  // 注意 s5 被移动了,不能继续使用, 调用fn add(self, s: &str) -> String
        println!("s7:{}",s7);  // s7:Hello Everyone
    
        let s8 = s7 + "xxx";
        println!("s8:{}",s8); // Hello Everyonexxx, 这表示可以拼接&str
    
        // format格式化
        let s1 = String::from("tic"); 
        let s2 = String::from("tac"); 
        let s3 = String::from("toe"); 
        let s = format!("{}-{}-{}", s1, s2, s3);
        println!("s:{}",s); // s:tic-tac-toe
    
        // 索引字符串
        // let h = s3[1];  // 报错,提示不支持索引字符串
        // 原因: String 是一个 Vec<u8> 的封装
    
        println!("{}",String::from("Hola").len()); // 4, 因为使用utf-8就能表示,所以一个字符占一个字节
        println!("{}",String::from("Здравствуйте").len()); // 24,使用的是Unicode,所以每个 Unicode 标量值需要两个字节存储
        let hello = "Здравствуйте"; 
        // let answer = &hello[0];  // 报错
    }
    

      Rust 不允许使用索引获取 String 字符的原因是,索引操作预期总是需要常数时间(O(1))。但是对于 String 不可能保证这样的性能,因为 Rust 必须从开头到索引位置遍历来确定有多少有效的字符。

     
     
     
  • 相关阅读:
    解决Struts中文乱码问题总结
    也谈创业企业CEO该拿多少工资
    Codeforces Round #242 (Div. 2) A. Squats
    设计模式之模板方法模式
    hdu2768Cat vs. Dog (反建法,最大独立集)
    Python
    kvm
    linux bin文件制作
    python
    pytho
  • 原文地址:https://www.cnblogs.com/double-W/p/13186040.html
Copyright © 2020-2023  润新知