刚开始学 Rust,这是一段创建一个原始数组的代码,有更“官方”的实现吗? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
0gre2019
V2EX    Rust

刚开始学 Rust,这是一段创建一个原始数组的代码,有更“官方”的实现吗?

  •  
  •   0gre2019 2020-09-20 10:53:22 +08:00 5421 次点击
    这是一个创建于 1859 天前的主题,其中的信息可能已经有所发展或是发生改变。
    原 Java 代码:
    int[] arr = new int[10];
    for(int i = 0;i < arr.length;i ++)
    arr[i] = i;

    我捣鼓的 Rust 代码:
    fn main() {
    let mut arr: [i32; 10] = [0; 10];

    for i in 0..arr.len() {
    arr[i] = i as i32;
    }
    }

    有个疑问:
    1. Rust 的原始数组似乎是没有“new”这种特性,即提前开辟一个空间。必须在声明时同时初始化?假如我如下面这样写:

    let mut arr: [i32; 10]; // 仅声明一个数组,未初始化

    那么 cargo check 会在 arr[i] = i as i32;处提示数组未初始化,有比我这个更好的写法吗,即数组初始化方法?

    (另外吐槽下 Rust 真的很严格,循环里的赋值代码必须写 as i32,好像不准隐式转换 usize 到 i32 。。)
    16 条回复    2020-09-23 18:38:40 +08:00
    Jirajine
        1
    Jirajine  
       2020-09-20 11:07:44 +08:00 via Android
    为什么要用原始数组呢,用 vector 啊。
    let v1:Vec<i32> = (1..10).collect();
    Jirajine
        2
    Jirajine  
       2020-09-20 11:15:17 +08:00 via Android
    至于初始化,直接声明的变量是分配在栈上的,编译时就已确定,所以不用额外分配空间。
    所有变量访问时必须初始化是 rust 静态检查的要求,未初始化当然可以赋值,只要访问前赋值了就行。
    你这个数组不能的原因是 arr[i]本身就是一次访问,调用 index 方法,而 rust 不允许访问未初始化的变量。
    0gre2019
        3
    0gre2019  
    OP
       2020-09-20 11:37:25 +08:00
    @Jirajine 因为刚学,想把一个 Java 实现的数据结构用 Rust 重写一下来练习。。
    noe132
        4
    noe132  
       2020-09-20 13:24:14 +08:00
    Java 在你 new 的时候自动帮你把每个值赋值初始值了。
    https://stackoverflow.com/a/3426854/6403587
    CSM
        5
    CSM  
       2020-09-20 13:34:08 +08:00 via Android
    你需要区分开引用类型与值类型。

    > 那么 cargo check 会在 arr[i] = i as i32;处提示数组未初始化

    这里的意思不是说数组的内容没有初始化(事实上,写入没有初始化的内存是允许的,并且是个重要的优化手段),而是指 arr 这个变量名字没有绑定到内存上,
    CSM
        6
    CSM  
       2020-09-20 13:43:54 +08:00
    > let mut arr: [i32; 10]; // 仅声明一个数组,未初始化

    这里只是定义了个名字。

    在 Java 中 `int[] arr` 的意思是定义一个引用,但是因为还没有被赋值,是 null 。
    在 C/C++ 中,`int arr[]` 后就已经在栈为数组预留了空间,此时已经可以写入了(虽然可以读取,但会是一些没用的数据,在 C/C++ 中给出警告,而 Rust 会禁止读取),但是在 Java 中还只是个指针,需要在堆为数组分配了内存(并赋值给这个指针)后才能写入。
    0gre2019
        7
    0gre2019  
    OP
       2020-09-20 15:51:29 +08:00
    @CSM 好像更理解了一些,谢谢
    qefrgty
        8
    qefrgty  
       2020-09-20 16:58:00 +08:00 via Android
    没有。数组必须在声明时直接初始化。

    单就你这段代码,能优化的地方就是第二行代码中的 :[i33;0] 可以删掉。

    写 rust 你就相信编译器并满足它就完事儿了。

    不过不必纠结数组,直接 vec 一把梭(大雾)
    0gre2019
        9
    0gre2019  
    OP
       2020-09-20 19:49:48 +08:00
    @qefrgty : )谢谢
    0gre2019
        10
    0gre2019  
    OP
       2020-09-20 19:51:44 +08:00
    我暂时解决了,大体是用 Box 包装了一下:
    #[derive(Debug)]
    pub struct Array {
    data: Box::<[i32]>,
    size: usize,
    }

    impl Array {
    pub fn new() -> Array {
    Array {
    data: Box::new([0; 100]),
    size: 0,
    }
    }
    }
    ldm0
        11
    ldm0  
       2020-09-20 22:00:33 +08:00
    ```rust
    use std::mem::{self, MaybeUninit};

    fn main() {
    let mut arr = unsafe {
    let data: [MaybeUninit<i32>; 10] = MaybeUninit::uninit().assume_init();
    mem::transmute::<_, [i32; 10]>(data)
    };

    for i in 0..arr.len() {
    arr[i] = i as i32;
    }

    dbg!(arr);
    }
    ```
    参见 <https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html>
    RedL0tus
        12
    RedL0tus  
       2020-09-21 04:55:06 +08:00 via iPhone
    说句题外话(

    原始数组各方面比较接近 C 的数组,用的时候基本上都是使用它的 immutable reference ;应用场景除了 slice 或者像 nom 那样搞 zero-copy 极致性能之外就没多少了(

    就我自己理解的话,一般用 Vec 是最合适的(反正 Vec 可以直接 AsRef 成 &[T]),还有一个 vec! 宏可以用,很方便的(
    0gre2019
        13
    0gre2019  
    OP
       2020-09-21 20:45:14 +08:00
    @ldm0 老哥你这是终极解决方案,我看了 Vec 的源码,基础数据类型就是 MaybeUninit<T>,谢了!
    CSM
        14
    CSM  
       2020-09-22 12:59:05 +08:00 via Android
    @ldm0 是不是 transmute 的太早了……
    ldm0
        15
    ldm0  
       2020-09-23 14:16:29 +08:00
    @CSM 确实是早的,但是题主要的就是这样。
    CSM
        16
    CSM  
       2020-09-23 18:38:40 +08:00 via Android
    @ldm0 不是,你这还没有初始化就转换了,虽说随后就写入了初始化的值,但创建未初始化的内存立马就是 UB 啊,不应该是初始化完成后再转换吗?
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     3325 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 23ms UTC 04:40 PVG 12:40 LAX 21:40 JFK 00:40
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86