• 2311rust到20版本更新


    Rust1.9

    Rust1.9中最大的变化是稳定了包括停止恐慌启动的展开过程方法的std::panic模块:

    use std::panic;
    let result = panic::catch_unwind(|| {
        println!("hello!");
    });
    assert!(result.is_ok());
    let result = panic::catch_unwind(|| {
        panic!("oh no!");
    });
    assert!(result.is_err());
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    1,已添加追加方法到BinaryHeap,BTreeMapBTreeSet中.此外,已添加split_offBTreeMap,因此BTreeSet::split_off.
    2,在libstdf32f64类型上,有to_degreesto_radians方法,但现在它们也在libcore中.
    3,Iterator有两个新方法:sumproduct
    4,CellRefCell都有了get_mut.
    5,与assert!一样,assert_eq!接受自定义错误消息.

    ?号

    Rust获得了个新的?符号,假设有从文件中读取一些数据:

    fn read_username_from_file() -> Result<String, io::Error> {
        let f = File::open("username.txt");
        let mut f = match f {
            Ok(file) => file,
            Err(e) => return Err(e),
        };
        let mut s = String::new();
        match f.read_to_string(&mut s) {
            Ok(_) => Ok(s),
            Err(e) => Err(e),
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    此代码两条可能失败路径,即打开文件,及从中读取数据.如果其中一个不管用,想从read_username_from_file返回错误.

    这里,涉及匹配I/O操作结果.但是,都是样板.
    ?,上面代码如下:

    fn read_username_from_file() -> Result<String, io::Error> {
        let mut f = File::open("username.txt")?;
        let mut s = String::new();
        f.read_to_string(&mut s)?;
        Ok(s)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    这是简写.即?针对Result值,如果它是Ok,则解包它并给出内部值.如果是Err,则从你当前所在的函数返回.

    1.13之前,read_username_from_file可这样实现:

    fn read_username_from_file() -> Result<String, io::Error> {
        let mut f = try!(File::open("username.txt"));
        let mut s = String::new();
        try!(f.read_to_string(&mut s));
        Ok(s)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    多次调用try时,非常没有吸引力;要用更甜蜜的语法.!是连续使用的.考虑:

    try!(try!(try!(foo()).bar()).baz())
    //对比
    foo()?.bar()?.baz()?
    
    • 1
    • 2
    • 3

    1.15.1稳定版

    此版本修复了两个问题,即新vec::IntoIter::as_mut_slice方法中的健全性错误,及Rust发布版的某些C组件未使用-fPIC编译的回归问题.

    as_mut_slice是个三行函数,在发布Rust1.15.0几分钟后就发现了该问题,提醒人们编写不安全代码的危险.
    as_mut_sliceVec类型的IntoIter迭代器上的一个方法,它提供了正在迭代缓冲可变视图.从概念上讲,它很简单:只需返回缓冲引用;
    事实上,实现很简单,但它是不安全的,因为IntoIter是用缓冲不安全指针实现的:

    pub fn as_mut_slice(&self) -> &mut [T] {
        unsafe {
            slice::from_raw_parts_mut(self.ptr as *mut T, self.len())
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    此方法带共享引用,且不安全地从可变引用继承.即as_mut_slice可生成同一缓冲多个可变引用,这是在Rust中是禁止的.

    下面说明该错误:

    fn main() {
        let v = vec![0];
        let v_iter = v.into_iter();
        let slice1: &mut [_] = v_iter.as_mut_slice();
        let slice2: &mut [_] = v_iter.as_mut_slice();
        slice1[0] = 1;
        slice2[0] = 2;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    这里slice1slice2引用了同一个可变切片.注意,v_iter迭代器未按可变声明,很可疑.
    修复很简单,只需将&self更改为&mut self:

    pub fn as_mut_slice(&mut self) -> &mut [T] {
        unsafe {
            slice::from_raw_parts_mut(self.ptr as *mut T, self.len())
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    这样,可保持唯一可变,且必须声明v_iter可变切片才能可变切片.

    1.17.0稳定版

    "静态生命期"现在假定为静态和常量.这样编写conststatic时:

    const NAME: &'static str = "Ferris";
    static NAME: &'static str = "Ferris";
    
    • 1
    • 2

    Rust1.17允许省略"",因为这是唯一有意义的生命期:

    const NAME: &str = "Ferris";
    static NAME: &str = "Ferris";
    
    • 1
    • 2

    有时,可删除大量样板:

    //老
    const NAMES: &'static [&'static str; 2] = &["Ferris", "Bors"];
    //新增功能
    const NAMES: &[&str; 2] = &["Ferris", "Bors"];
    
    • 1
    • 2
    • 3
    • 4

    另一个类似改进叫"对象字面属性速记",在声明结构时可删除重复项,如下:

    //定义
    struct Point {
        x: i32,
        y: i32,
    }
    let x = 5;
    let y = 6;
    //老
    let p = Point {
        x: x,
        y: y,
    };
    //新增功能
    let p = Point {
        x,
        y,
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    也即,x,y形式假定设置其值为域中同名变量.
    新手容易,把两个&strs在一起.这不管用,只能String+&str.因此.

    //代码
    "foo" + "bar"
    //旧
    error[E0369]: binary operation `+` cannot be applied to type `&'static str`
     --> <anon>:2:5
      |
    2 |     "foo" + "bar"
      |     ^^^^^
      |
    note: an implementation of `std::ops::Add` might be missing for `&'static str`
     --> <anon>:2:5
      |
    2 |     "foo" + "bar"
      |     ^^^^^
    //新加功能
    error[E0369]: binary operation `+` cannot be applied to type `&'static str`
     --> <anon>:2:5
      |
    2 |     "foo" + "bar"
      |     ^^^^^
      |
      = note: `+` can't be used to concatenate two `&str` strings
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    help:to_owned()可从创建"物主串"

    引用.把连接到右侧的串
    可能需要重新分配.这需要串的所有权

      |     "foo".to_owned() + "bar"
    
    • 1

    使用Cargo的构建脚本时,必须在Cargo.toml中设置脚本位置.然而,绝大多数人都写为build="build.rs",在项目的根目录中使用build.rs文件.

    此约定现在已编码到Cargo中,如果存在build.rs,则假定此约定.可用build=false选出.

    扩展了一点pub关键字.

    pub(crate) bar;
    
    • 1

    ()里面是"限制位",补充如何公开.上例一样使用crate关键字,表明bar对整个crate但不是在它之外,是公开的.

    这样可更轻松地声明"对crate公开"但不向用户公开的API.
    还可指定路径,如下:

    pub(in a::b::c) foo;
    
    • 1

    即仅在a::b::c的层次中可用,其他地方不可用.
    窗口用户,Rust1.18.0有个新属性,#![windows_subsystem].工作原理如下:

    #![windows_subsystem = "console"]
    #![windows_subsystem = "windows"]
    
    • 1
    • 2

    控制链接器中的/SUBSYSTEM标志.目前,仅支持"控制台"和"窗口".

    最后,Rust(没有#[repr])的元组,枚举变体字段和结构总是有个未限定的布局.开启了自动重排功能,可减少填充来减小尺寸.考虑此结构:

    struct Suboptimal(u8, u16, u8);
    
    • 1

    x86_64平台上的Rust早期版本中,此结构的大小为6个字节.但查看源码,会期望有四个字节.额外的两个字节用来填充;

    但是,如果像这样呢

    struct Optimal(u8, u8, u16);
    
    • 1

    Rust1.19.0

    第一个支持的版本:

    union MyUnion {
        f1: u32,
        f2: f32,
    }
    
    • 1
    • 2
    • 3
    • 4

    类似枚举,但它们没有"标签"的.枚举有运行时决定存储哪个变体的"标签";省略了该标签.
    因为可用错误变体解释联中保存数据,而Rust无法检查这一点,即读写联字段是不安全的:

    let u = MyUnion { f1: 1 };
    unsafe { u.f1 = 5 };
    let value = unsafe { u.f1 };
    
    • 1
    • 2
    • 3

    模式匹配也有效:

    fn f(u: MyUnion) {
        unsafe {
            match u {
                MyUnion { f1: 10 } => { println!("ten"); }
                MyUnion { f2 } => { println!("{}", f2); }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    主要用来与C互操作.
    循环现在可中断一个值:

    //旧代码
    let x;
    loop {
        x = 7;
        break;
    }
    //新代码
    let x = loop { break 7; };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    不抓环境的闭包现在可转换为函数指针:

    let f: fn(i32) -> i32 = |x| x + 1;
    
    • 1

    1.20.0稳定版

    以前Rust版本中,已可定义有"关联函数"特征,结构和枚举:

    struct Struct;
    impl Struct {
        fn foo() {
            println!("foo是构的关联函数");
        }
    }
    fn main() {
        Struct::foo();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    还增加了定义"关联常量"的功能:

    struct Struct;
    impl Struct {
        const ID: u32 = 0;
    }
    fn main() {
        println!("id为: {}", Struct::ID);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    也即,常量IDStruct相关联.与函数一样,关联常量也适合特征和枚举.
    特征,可像使用关联类型一样使用关联常量:声明它,但不给它一个值.
    然后,特征实现者在实现声明其值:

    trait Trait {
        const ID: u32;
    }
    struct Struct;
    impl Trait for Struct {
        const ID: u32 = 5;
    }
    fn main() {
        println!("{}", Struct::ID);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    此版本之前,必须如下写:

    trait Float {
        fn nan() -> Self;
        fn infinity() -> Self;
        ...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    这有点笨拙,且因为是函数,即使只返回一个常量,也不能在常量式中使用它们.因此,Float的设计还必须包含常量:

    mod f32 {
        const NAN: f32 = 0.0f32 / 0.0f32;
        const INFINITY: f32 = 1.0f32 / 0.0f32;
        impl Float for f32 {
            fn nan() -> Self {
                f32::NAN
            }
            fn infinity() -> Self {
                f32::INFINITY
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    通过关联常量,可更简洁地如下定义特征:

    trait Float {
        const NAN: Self;
        const INFINITY: Self;
        ...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    实现:

    mod f32 {
        impl Float for f32 {
            const NAN: f32 = 0.0f32 / 0.0f32;
            const INFINITY: f32 = 1.0f32 / 0.0f32;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    更干净,更通用.
    还修复了include!文档测试中的:
    首先,改了一些字面.考虑如下代码:

    let x = &5;
    
    • 1

    Rust中,这段代码等价:

    let _x = 5;
    let x = &_x;
    
    • 1
    • 2

    也即,这里在中存储,或可能在寄存器中存储5.x是引用它.

    但是,因为它是个整数字面,因此不必是局部的.考虑,有个带静态参数的函数,如std::thread::spawn.可这样使用x:

    use std::thread;
    fn main() {
        let x = &5;
        thread::spawn(move || {
            println!("{}", x);
        });
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在以前的Rust版本中,这无法编译:

    error[E0597]: borrowed value does not live long enough
      --> src/main.rs:4:14
       |
    4  |     let x = &5;
       |              ^ does not live long enough
    ...
    10 | }
       | - temporary value only lives until here
       |
     注意:借入的值必须在`静态`生命期内有效...
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    因为5是局部的,所以它的借用也是局部的,这不符合生成要求.

    但是,如果在Rust1.21上编译它,它将起作用.为什么?好吧,如果可把引用数据放入中,可化简为如下let x=&5;:

    static FIVE: i32 = 5;
    let x = &FIVE;
    
    • 1
    • 2

    在此,因为FIVE静态的,因此x是&'静态 i32.

    现在生成代码时并行运行LLVM.

    1.22.01.22.1稳定版

    现在可用Option!
    Rust1.22中,Option现在是稳定的.此代码现在编译:

    fn add_one_to_first(list: &[u8]) -> Option<u8> {
        //如果存在,取第一个元素,如果不存在,则返回`None`
        let first = list.get(0)?;
        Some(first + 1)
    }
    assert_eq!(add_one_to_first(&[10, 20, 30]), Some(11));
    assert_eq!(add_one_to_first(&[]), None);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    现在允许在conststatic项中,实现Drop的类型如下:

    struct Foo {
        a: u32,
    }
    impl Drop for Foo {
        fn drop(&mut self) {}
    }
    const F: Foo = Foo { a: 0 };
    static S: Foo = Foo { a: 0 };
    //常/静
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    会增强常和静功能.
    现在T op=&T适合原语类型:

    let mut x = 2;
    let y = &8;
    //以前不行,但现在可以了
    x += y;
    
    • 1
    • 2
    • 3
    • 4

    以前,需要写x+=*y才能解引用.
    1,Box现在隐含From>
    2,std::mem::Discriminant现在保证为发送+同步
    3,fs::copy现在返回NTFS上主流的长度.
    4,正确检测Instant+=Duration中的溢出.
    5,impl Hasher for {&mutHasher,Box}
    6,impl fmt::Debug for SplitWhitespace.

  • 相关阅读:
    MySQL数据库之索引
    多云环境的风险发现
    HTML+CSS+JS:花瓣登录组件
    (附源码)springboot流浪动物救助系统 毕业设计 180920
    Timed out waiting for device dev-ttymxc3.device.
    Nodejs -- 一文学会如何在Express中使用JWT(json web token)
    元宇宙007 | 沉浸式家庭治疗,让治疗像演情景剧一样!
    韩国锂电池工厂火灾:行业安全警钟再次敲响
    为你的网站加上和风天气插件
    OpenCV图像处理学习一,加载显示修改保存图像相关函数
  • 原文地址:https://blog.csdn.net/fqbqrr/article/details/134423391