ฉันจะสร้างอาร์เรย์ขนาดคงที่ของสตริงโดยใช้ค่าคงที่ได้อย่างไร

Aug 17 2020

ฉันมีฟังก์ชันที่ใช้ค่าคงที่ทั่วไป:

fn foo<const S: usize>() -> Vec<[String; S]> {
    // Some code
    let mut row: [String; S] = Default::default(); //It sucks because of default arrays are specified up to 32 only
    // Some code
}

ฉันจะสร้างอาร์เรย์ขนาดคงที่Stringในกรณีของฉันได้อย่างไร let mut row: [String; S] = ["".to_string(), S];ไม่ได้ผลเพราะStringไม่ได้ใช้Copyลักษณะ

คำตอบ

4 eggyal Aug 17 2020 at 23:49

คุณสามารถทำได้ด้วยMaybeUninitและunsafe:

use std::mem::MaybeUninit;

fn foo<const S: usize>() -> Vec<[String; S]> {
    // Some code

    let mut row: [String; S] = unsafe {
        let mut result = MaybeUninit::uninit();
        let start = result.as_mut_ptr() as *mut String;
        
        for pos in 0 .. S {
            // SAFETY: safe because loop ensures `start.add(pos)`
            //         is always on an array element, of type String
            start.add(pos).write(String::new());
        }

        // SAFETY: safe because loop ensures entire array
        //         has been manually initialised
        result.assume_init()
    };

    // Some code

    todo!()
}

แน่นอนว่ามันอาจจะง่ายกว่าที่จะเอาตรรกะดังกล่าวไปใช้กับลักษณะของคุณเอง:

use std::mem::MaybeUninit;

trait DefaultArray {
    fn default_array() -> Self;
}

impl<T: Default, const S: usize> DefaultArray for [T; S] {
    fn default_array() -> Self {
        let mut result = MaybeUninit::uninit();
        let start = result.as_mut_ptr() as *mut T;
        
        unsafe {
            for pos in 0 .. S {
                // SAFETY: safe because loop ensures `start.add(pos)`
                //         is always on an array element, of type T
                start.add(pos).write(T::default());
            }

            // SAFETY: safe because loop ensures entire array
            //         has been manually initialised
            result.assume_init()
        }
    }
}

(เหตุผลเดียวในการใช้ลักษณะของคุณเองมากกว่าDefaultคือการใช้งานแบบหลังจะขัดแย้งกับที่ให้ไว้ในไลบรารีมาตรฐานสำหรับอาร์เรย์สูงสุด 32 องค์ประกอบฉันคาดหวังว่าไลบรารีมาตรฐานจะแทนที่การใช้งานDefaultด้วยสิ่งที่คล้ายกับ ข้างต้นเมื่อ const generics เสถียรแล้ว)

ซึ่งในกรณีนี้คุณจะมี:

fn foo<const S: usize>() -> Vec<[String; S]> {
    // Some code

    let mut row: [String; S] = DefaultArray::default_array();

    // Some code

    todo!()
}

เห็นมันในสนามเด็กเล่น