我正在尝试初始化一些可以为空的非可复制类型的固定大小数组,就像某种Option<Box<Thing>>
的{{1}}一样。我想把它们中的两个打包成一个没有任何额外间接的结构。我想写这样的东西:
Thing
但它不起作用,因为let array: [Option<Box<Thing>>; SIZE] = [None; SIZE];
语法要求[e; n]
实现e
。当然,我可以将其扩展为Copy
SIZE
s,但是当None
很大时,这可能会很笨拙。如果没有SIZE
的非自然编码,我不相信这可以用宏来完成。有没有好办法呢?
是的,SIZE
这很容易;有没有办法在没有unsafe
的情况下完成?
答案 0 :(得分:8)
您可以使用Default
特征使用默认值初始化数组:
let array: [Option<Box<Thing>>; SIZE] = Default::default();
有关工作示例,请参阅this playground。
答案 1 :(得分:7)
从 Rust 1.38(于 2019 年 9 月发布)开始,可以使用中间 const
初始值设定项来替代现有答案。这种方法适用于任何大小的数组:
const SIZE: usize = 100;
const INIT: Option<Box<Thing>> = None;
let array: [Option<Box<Thing>>; SIZE] = [INIT; SIZE];
(无论有没有 Box
都可以使用;示例使用 Box
,因为它在问题中使用过。)
一个限制是数组项必须有一个可以在编译时计算的默认表示——常量、枚举变量或由这些组成的原始容器。 None
或一组数字会起作用,但非空的 Vec
或 String
不会。
答案 2 :(得分:3)
我正在复制the answer by chris-morgan并对其进行调整以更好地匹配问题,以遵循dbaupp downthread的建议,并匹配最近的语法更改:
use std::mem;
use std::ptr;
#[derive(Debug)]
struct Thing {
number: usize,
}
macro_rules! make_array {
($n:expr, $constructor:expr) => {{
let mut items: [_; $n] = mem::uninitialized();
for (i, place) in items.iter_mut().enumerate() {
ptr::write(place, $constructor(i));
}
items
}}
}
const SIZE: usize = 50;
fn main() {
let items = unsafe { make_array!(SIZE, |i| Box::new(Some(Thing { number: i }))) };
println!("{:?}", &items[..]);
}
注意这里需要使用unsafe
:问题是如果构造函数函数panic!
,这将导致未定义的行为。
答案 3 :(得分:0)
这是“保持简单”的答案:只需键入所有值:
Strip /Users/germanparisi/Library/Developer/Xcode/DerivedData/Hospital_Virtual_Testing-bciuaksocglhbjbwocwoopwsdild/Build/Intermediates.noindex/ArchiveIntermediates/Hospital\ Virtual\ Testing/IntermediateBuildFilesPath/UninstalledProducts/iphoneos/libCordova.a
cd /Users/germanparisi/pabex/hospitalvirtualweb/hospital_virtual/app/platforms/ios/CordovaLib
export PATH="/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin:/Applications/Xcode.app/Contents/Developer/usr/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin"
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/strip -S -T /Users/germanparisi/Library/Developer/Xcode/DerivedData/Hospital_Virtual_Testing-bciuaksocglhbjbwocwoopwsdild/Build/Intermediates.noindex/ArchiveIntermediates/Hospital\ Virtual\ Testing/IntermediateBuildFilesPath/UninstalledProducts/iphoneos/libCordova.a
fatal error: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/strip: can't open temporary file: /tmp/strip.7t2R7O (Permission denied)
Command /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/strip failed with exit code 1
您还可以使用a build script为您生成此代码。有关此示例,请参见:
答案 4 :(得分:0)
使用 arrayvec
板条箱的另一种方法可以轻松地推广到除使用固定值初始化所有内容之外的情况:
use arrayvec::ArrayVec;
let array = std::iter::repeat(None)
.take(SIZE)
.collect::<ArrayVec<Option<Box<Thing>>, SIZE>>()
.into_inner()
.unwrap();