• 2311rust到31版本更新


    1.27.1稳定版

    在此修补程序前,下例在编译器内部恐慌.

    fn main() {
        let a = vec!["".to_string()];
        a.iter().enumerate()
                .take_while(|(_, &t)| false)
                .collect::<Vec<_>>();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    1.27.1拒绝上述代码,并显示以下错误消息:

    error[E0507]: cannot move out of borrowed content
        --> src/main.rs:4:30
        |
      4 |             .take_while(|(_, &t)| false)
        |                              ^-
        |                              ||
        |                              |hint: to prevent move, use `ref t` or `ref mut t`
        |                              cannot move out of borrowed content
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    1.27.2稳定版

    fn transmute_lifetime<'a, 'b, T>(t: &'a (T,)) -> &'b T {
        match (&t, ()) {
            ((t,), ()) => t,
        }
    }
    fn main() {
        let x = {
            let y = Box::new((42,));
            transmute_lifetime(&y)
        };
        println!("{}", x);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    1.27.2拒绝上述代码.

    1.28.0稳定版

    全局分配器
    分配器是Rust中程序,运行时从系统取内存的方式.以前,Rust禁止改变取内存方式,这阻止了某些用例.在某些平台上,即使用jemalloc,在其他平台上,即使用系统分配器,但用户无法控制此关键组件.

    1.28.0中,#[global_allocator]属性现在是稳定的,它允许Rust程序设置分配器系统分配器,并通过实现GlobalAlloc特征来定义新的分配器.

    某些平台上Rust程序的默认分配器是jemalloc.标准库现在提供了需要时可切换到的系统分配器句柄,只需要声明为静态并用#[global_allocator]属性标记它.

    use std::alloc::System;
    #[global_allocator]
    static GLOBAL: System = System;//系统
    fn main() {
        let mut v = Vec::new();
        //这使用系统分配器分配内存.
        v.push(1);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    但是,有时想为给定的应用域自定义分配器.实现GlobalAlloc特征即可.

    改进了设置格式的错误消息
    仍在诊断,重点是格式:

    format!("{_foo}", _foo = 6usize);
    
    • 1

    以前,错误消息相对较差:

    error: invalid format string: expected `'}'`, found `'_'`
      |
    2 |     format!("{_foo}", _foo = 6usize);
      |             ^^^^^^^^
    
    • 1
    • 2
    • 3
    • 4

    现在,诊断并告诉格式串无效的具体原因:
    错误:格式串无效:"_foo"参数名无效

      |
    2 |     let _ = format!("{_foo}", _foo = 6usize);
      |                       ^^^^ invalid argument name in format string
      |
      = note: argument names cannot start with an underscore
    
    • 1
    • 2
    • 3
    • 4
    • 5

    库稳定

    另一个重要稳定性是非零数类型.这些是标准:NonZeroU8,NonZeroU16,NonZeroU32,NonZeroU64,NonZeroU128NonZeroUsize正整数类型的包装器.

    这允许大小优化,如,Option有两个字节大,但Option只有一个字节大.注意,即使NonZeroU8在另一个结构中包装,也有此优化;
    下例说明,尽管在Option中放置Door,但仍有1个字节大.优化也适合用户定义的枚举:Option并不特殊.

    use std::mem;
    use std::num::NonZeroU8;
    struct Key(NonZeroU8);
    struct Door {
        key: Key,
    }
    fn main() {
        assert_eq!(mem::size_of::<Door>(), 1);
        assert_eq!(mem::size_of::<Option<Door>>(), 1);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    Cargo现在不再允许发布修改src目录构建脚本的crate.crate中的src目录应该是不变的.

    1.29.0稳定版

    cargo fix可自动修复带警告代码
    cargo clippy是一堆抓常见错误并改进Rust代码的lints.

    货物修复
    子命令:cargo fix.如果你以前用Rust编写过代码,你可能以前见过编译器警告.如,考虑:

    fn do_something() {}
    fn main() {
        for i in 0..100 {
            do_something();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在此,调用了100do_something.但从不使用i变量.所以Rust警告说:

    cargo build
       Compiling myprogram v0.1.0 (file:///path/to/myprogram)
    warning: unused variable: `i`
     --> src\main.rs:4:9
      |
    4 |     for i in 1..100 {
      |         ^ help: consider using `_i` instead
      |
      = note: #[warn(unused_variables)] on by default
        Finished dev [unoptimized + debuginfo] target(s) in 0.50s
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    因此,它建议改用_i.可自动修复:

    cargo fix
        Checking myprogram v0.1.0 (file:///C:/用户/steve/tmp/fix)
          Fixing src\main.rs (1 fix)
        Finished dev [unoptimized + debuginfo] target(s) in 0.59s
    
    • 1
    • 2
    • 3
    • 4

    如果再次查看src\main.rs,会看到代码已更改:

    fn do_something() {}
    fn main() {
        for _i in 0..100 {
            do_something();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    现在使用的是_i,将不再有警告.
    现在可用Rustup查看cargo clippy的预览.Clippy是可针对Rust代码运行的大量额外警告.
    如:

    let mut lock_guard = mutex.lock();
    std::mem::drop(&lock_guard)
    operation_that_requires_mutex_to_be_unlocked();
    
    • 1
    • 2
    • 3

    代码语法上是正确的,但可能有死锁!你看,删除了lock_guard的引用,而不是警卫自身.删除引用是个空操作,因此这几乎可肯定是个错误.

    可从Rustup获得Clippy的预览:

    rustup component add clippy-preview
    
    • 1

    然后运行它:

    cargo clippy
    
    • 1
    error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing.
     --> src\main.rs:5:5
      |
    5 |     std::mem::drop(&lock_guard);
      |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
      |
      = note: #[deny(drop_ref)] on by default
    note: argument has type &std::result::Result<std::sync::MutexGuard<'_, i32>, std::sync::PoisonError<std::sync::MutexGuard<'_, i32>>>
     --> src\main.rs:5:20
      |
    5 |     std::mem::drop(&lock_guard);
      |                    ^^^^^^^^^^^
      = help: for further information visit https://rust-lang-nursery.github.io/rust-clippy/v0.0.212/index.html#drop_ref
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    帮助消息中可看出,可查看clippy提供的所有lint.
    库稳定
    此版本稳定了三个API:

    Arc<T>::downcast
    Rc<T>::downcast
    Iterator::flatten
    
    • 1
    • 2
    • 3

    此外,现在可比较&strOsString.

    除此外,Cargo现在试修复已被git合并破坏的锁文件.可传递--locked禁止此行为.
    cargo doc还增加了一个新标志:--document-private-items.默认,cargo doc只文档化公开内容.
    但是,如果在处理自己的crate,且有供自己参考的内部文档,--document-private-items项为所有而不仅是公开项目生成文档.

    1.29.1稳定版

    如果传递大数str::repeat,可能导致整数溢出后的缓冲溢出.如果不调用str::repeat函数,则不受影响.
    已解决.

    1.30.0稳定版

    过程宏

    早在Rust1.15中,就宣布了可定义"自定义继承"的功能.如,使用serde_derive,你可

    #[derive(Serialize, Deserialize, Debug)]
    struct Pet {
        name: String,
    }
    
    • 1
    • 2
    • 3
    • 4

    并用serde_json相互转换PetJSON,因为serde_derive过程宏中定义了SerializeDeserialize.
    Rust1.30在此基础上扩展,增加了定义另外两个"类属性过程宏"和"类函数过程宏",高级宏的能力.

    类似属性类似自定义继承宏,但它们不是仅为#[derive]属性生成代码,且允许创建自己的自定义属性.
    也更灵活:继承仅适合结构和枚举,但属性可放在比如函数等地方.作为使用类似属性的宏的示例,在使用Web应用框架时,可能有类似此的内容:

    #[route(GET, "/")]
    fn index() {
    
    • 1
    • 2

    #[route]属性由框架自身按过程宏定义.签名如下:

    #[proc_macro_attribute]
    pub fn route(attr: TokenStream, item: TokenStream) -> TokenStream {
    
    • 1
    • 2

    在此,有两个输入TokenStreams:第一个是属性自身的内容,即GET与"/"的东西.第二个是属性附加到的主体,本例中为fn index(){}函数主体的其余部分.
    类似函数的宏定义类似调用函数的宏.如,gnome-class仓库有个定义Rust中的GObject类的过程宏:

    gobject_gen!(
        class MyClass: GObject {
            foo: Cell<i32>,
            bar: RefCell<String>,
        }
        impl MyClass {
            virtual fn my_virtual_method(&self, x: i32) {
                //...用X做点什么......
            }
        }
    )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    就像以一堆代码参数函数.此宏定义如下:

    #[proc_macro]
    pub fn gobject_gen(input: TokenStream) -> TokenStream {
    
    • 1
    • 2

    类似继承宏的签名:取括号内的令牌,并返回要生成的代码.

    用和宏

    现在,可用use关键字把宏引入域中.如,要使用serde-jsonjson宏,过去这样:

    #[macro_use]
    extern crate serde_json;
    let john = json!({
        "name": "John Doe",
        "age": 43,
        "phones": [
            "+44 1234567",
            "+44 2345678"
        ]
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    但现在,你会这样:

    extern crate serde_json;
    use serde_json::json;//使用.
    let john = json!({
        "name": "John Doe",
        "age": 43,
        "phones": [
            "+44 1234567",
            "+44 2345678"
        ]
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    使宏与其他项目更一致,且无需macro_use注解.

    最后,proc_macro仓库已稳定,为你提供了编写此类宏期望的API.还显著改进了API错误,且像synquote等仓库已在使用它们.如,之前:

    #[derive(Serialize)]
    struct Demo {
        ok: String,
        bad: std::thread::Thread,
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    给出此错误:

    error[E0277]: the trait bound `std::thread::Thread: _IMPL_SERIALIZE_FOR_Demo::_serde::Serialize` is not satisfied
     --> src/main.rs:3:10
      |
    3 | #[derive(Serialize)]
      |          ^^^^^^^^^ the trait `_IMPL_SERIALIZE_FOR_Demo::_serde::Serialize` is not implemented for `std::thread::Thread`
    
    • 1
    • 2
    • 3
    • 4
    • 5

    现在给出:

    error[E0277]: the trait bound `std::thread::Thread: serde::Serialize` is not satisfied
     --> src/main.rs:7:5
      |
    7 |     bad: std::thread::Thread,
      |     ^^^ the trait `serde::Serialize` is not implemented for `std::thread::Thread`
    
    • 1
    • 2
    • 3
    • 4
    • 5

    改进模块系统

    首先是现在预引入外部仓库,即:

    //旧
    let json = ::serde_json::from_str("...");
    //新增功能
    let json = serde_json::from_str("...");
    
    • 1
    • 2
    • 3
    • 4

    因为Rust模块,并不总是需要"旧"风格:

    extern crate serde_json;
    fn main() {
        //这很好;在仓库根目录下,所以在此`"serde_json"`在域内
        let json = serde_json::from_str("...");
    }
    mod foo {
        fn bar() {
             //这不行;在`"foo"`名字空间中,且未在此声明`"serde_json"`
            let json = serde_json::from_str("...");
        }
        //一个选项,是在模块内"用"它
        use serde_json;
        fn baz() {
             //另一个选项是使用`'::serde_json'`,因此用的是`绝对`路径而不是相对路径
     
            let json = ::serde_json::from_str("...");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    移动函数到子模块并中断一些代码,并不好.现在,它检查路径的第一部分,查看它是否是个外部仓库,如果是,无论模块层次位置,都可用它.

    最后,use还支持引入crate开头的带路径项至域:

    mod foo {
        pub fn bar() {
            //...
        }
    }
    //旧
    use ::foo::bar;
    //或
    use foo::bar;
    //新增功能
    use crate::foo::bar;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    crate关键字表示想从crate根目录开始路径.以前,后指定路径总是从crate根目录开始,但直接引用项目的路径从本地路径开始,即路径行为不一致:

    mod foo {
        pub fn bar() {
            //...
        }
    }
    mod baz {
        pub fn qux() {
            //旧
            ::foo::bar();
            //不管用,这与`"use"`不同:`foo::bar();`
            //新增功能
            crate::foo::bar();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    所有这些变化结合在一起,可更直接理解路径的解析方式.除了use语句,一旦看到像a::b::c此路径,你都可如下:
    1,是仓库名字,然后在里面找b::c.
    2,是crate关键字,则从crate的根目录中找b::c.
    3,否则,从模块当前位置查找a::b::c.

    仍适用,总是从crate根目录开始使用路径的旧行为.但是,在切换到新风格后,给路径统一应用这些规则,这样移动代码时,要调整导入的次数要少得多.

    原始标识

    现在,可用一些新语法,用关键字作为标识:

    //定义叫`"for"`的局部变量
    let r#for = true;
    //定义叫`"for"`的函数
    fn r#for() {
        //...
    }
    //调用该函数
    r#for();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    此版本稳定了一些新API:

    Ipv4Addr::{BROADCAST, LOCALHOST, UNSPECIFIED}
    Ipv6Addr::{LOCALHOST, UNSPECIFIED}
    Iterator::find_map
    
    • 1
    • 2
    • 3

    此外,trim_left等功能,可消除某些文本一侧的空白.但是,在考虑从右到左(RTL)语言时,会混淆"右"和"左"含义.
    因此,给这些API引入新名:

    trim_left -> trim_start
    trim_right -> trim_end
    trim_left_matches -> trim_start_matches
    trim_right_matches -> trim_end_matches
    
    • 1
    • 2
    • 3
    • 4

    该版本中,Cargo最大的特点是现在有个进度栏!

  • 相关阅读:
    【java】Java中的异步实现方式
    【C语言】字符串函数及模拟实现strlen&&strcpy&&strcat&&strcmp
    3D模型转换工具HOOPS Exchange如何实现OBJ格式轻量化?
    Java程序设计-韩建平-读书笔记
    多边形内部水平方向近似最大矩形python实现
    小程序年度盘点&趋势预测
    立可得_第9章_统计分析
    R生成三线表
    通讯网关软件008——利用CommGate X2Mysql实现OPC数据转储Mysql
    Springboot视图解析与模板引擎~
  • 原文地址:https://blog.csdn.net/fqbqrr/article/details/134458652