- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我目前正在学习Rust,这很有趣。我在C/C++方面有一些经验,并且在其他使用更通用的范式(如泛型)的编程语言中也有其他经验。
背景
对于我的第一个项目(在本教程之后),我想创建一个N维数组(或Matrix)数据结构来练习Rust的开发。
到目前为止,这里是我的Matrix结构,基本填充和新初始化的内容。
原谅缺少边界检查和参数测试
pub struct Matrix<'a, T> {
data: Vec<Option<T>>,
dimensions: &'a [usize],
}
impl<'a, T: Clone> Matrix<'a, T> {
pub fn fill(dimensions: &'a [usize], fill: T) -> Matrix<'a, T> {
let mut total = if dimensions.len() > 0 { 1 } else { 0 };
for dim in dimensions.iter() {
total *= dim;
}
Matrix {
data: vec![Some(fill); total],
dimensions: dimensions,
}
}
pub fn new(dimensions: &'a [usize]) -> Matrix<'a, T> {
...
Matrix {
data: vec![None; total],
dimensions: dimensions,
}
}
}
我想要使用New fn创建“空” N维数组的功能。我认为使用Option枚举将是完成此操作的最佳方法,因为我可以用
None
填充N维,并且它将自动为此T泛型分配空间。
IndexMut
和
Index
特性看起来像我可以做的类似
m[&[2, 3]] = 23
。由于逻辑彼此相似,因此这里是
IndexMut
的
Matrix
impl。
impl<'a, T> ops::IndexMut<&[usize]> for Matrix<'a, T> {
fn index_mut(&mut self, indices: &[usize]) -> &mut Self::Output {
match self.data[get_matrix_index(self.dimensions, indices)].as_mut() {
Some(x) => x,
None => {
NOT SURE WHAT TO DO HERE.
}
}
}
}
理想情况下,将更改值(如果存在),即
let mut mat = Matrix::fill(&[4, 4], 0)
mat[&[2, 3]] = 23
这会将值设置为0到23(上面的fn通过从
&mut x
返回
Some(x)
来实现)。但我也希望
None
设置值,即
let mut mat = Matrix::new(&[4, 4])
mat[&[2, 3]] = 23
问题
m[&[2,3]] = 23
符合Vec结构分配内存的要求?如果不是的话,我应该改变什么,以及如何仍然有一个带有“空”点的阵列。在我尝试学习时,请接受任何建议。 :)
T
类型,并且必须对其进行大小调整。这对于通过
vec![pointer of T that is null but of size of T; total]
分配适当大小的Vec可能很有用。但是我不确定该怎么做。
最佳答案
因此,有几种方法可以使它更类似于惯用的 rust ,但首先让我们看看为什么none分支没有意义。
因此,我将假定的Output
的IndexMut
类型为&mut T
,因为您没有显示索引定义,但在这种假设下我觉得很安全。类型&mut T
意味着对初始化的T
的可变引用,这与C/C++中的指针可以指向已初始化或未初始化的内存不同。这意味着您必须返回一个初始化的T
,由于没有初始化值,none分支无法执行此操作。这导致了第一种更惯用的方式。
返回一个Option<T>
最简单的方法是将Index::Output
更改为Option<T>
。这样会更好,因为如果用户之前没有任何值(value)并且与您实际存储的内容接近,则用户可以决定该做什么。然后,您还可以在索引方法中消除 panic ,并允许调用方选择在没有值的情况下该怎么做。在这一点上,我认为您可以在下一个选项中对结构进行高级化处理。
直接存储T
此方法允许调用者直接更改存储的类型,而不是将其包装在选项中。这样就可以很好地清理您的大多数索引代码,因为您只需要访问已存储的内容即可。现在的主要问题是初始化,您如何表示未初始化的值?您是正确的,该选项是执行此操作的最佳方法1,但是现在调用者可以通过自己存储一个Option
来决定具有此可选的初始化功能。因此,这意味着我们始终可以存储已初始化的T
,而不会失去功能。这只会真正更改您的新函数,而不会填充None
值。我的建议是为新功能2绑定(bind)T: Default
:
impl<'a, T: Default> Matrix<'a, T> {
pub fn new(dimensions: &'a [usize]) -> Matrix<'a, T> {
Matrix {
data: (0..total).into_iter().map(|_|Default::default()).collect(),
dimensions: dimensions,
}
}
}
该方法在rust世界中更为常见,它允许调用者选择是否允许未初始化的值。
Option<T>
还为所有
T
实现默认值并返回
None
,因此该功能与您当前拥有的功能非常相似。
'static
,但是如果您使用动态尺寸,则不会发生这种情况。
'static
生存期(与无生存期相同)?因为您要一个N维数组,所以堆栈分配是不可能的,因为堆栈数组在编译时必须是确定性的(在rust中也称为
const
)。这意味着您必须使用堆。剩下两个实选项
Box<[usize]>
或
Vec<usize>
。
Box
只是表示这是在堆上的另一种方式,并将
Sized
添加到
?Sized
的值中。
Vec
有点不言自明,并增加了调整大小的能力,但付出了一些额外的开销。要么允许您的矩阵对象始终具有
'static
生存期。
Option<T>
的另一种表示方法是MaybeUninit<T>
,它是不安全的区域。这使您可以拥有一块足够大的初始化内存来容纳T
,然后假定它是不安全地初始化的。这可能会导致很多问题,通常不值得这样做,因为Option
已经进行了优化,如果它使用指针存储类型,则使用编译器魔术来存储该值是否为空指针的区别。vec![Default::default(); total]
的原因是,这需要T: Clone
作为该宏的工作方式,因此第一部分被调用一次并被克隆,直到有足够的值为止。这是我们不需要的一个额外要求,因此没有它,界面将更加平滑。关于rust - Rust数据结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66235902/
编辑备注 由于 Rust(版本:1.42)仍然没有稳定的 ABI ,推荐使用extern (目前相当于extern "C"(将来可能会改变))否则,可能需要重新编译库。 This article解释如
词法分析器/解析器文件位于 here非常大,我不确定它是否适合只检索 Rust 函数列表。也许我自己编写/使用另一个库是更好的选择? 最终目标是创建一种执行管理器。为了上下文化,它将能够读取包装在函数
我试图在 Rust 中展平 Enum 的向量,但我遇到了一些问题: enum Foo { A(i32), B(i32, i32), } fn main() { let vf =
我正在 64 位模式下运行的 Raspberry Pi 3 上使用 Rust 进行裸机编程。我已经实现了一个自旋锁,如下所示: use core::{sync::atomic::{AtomicBool
我无法理解以下示例是如何从 this code 中提炼出来的, 编译: trait A: B {} trait B {} impl B for T where T: A {} struct Foo;
在我写了一些代码和阅读了一些文章之后,我对 Rust 中的移动语义有点困惑,我认为值移动后,它应该被释放,内存应该是无效的。所以我尝试写一些代码来作证。 第一个例子 #[derive(Debug)]
https://doc.rust-lang.org/reference/types/closure.html#capture-modes struct SetVec { set: HashSe
考虑 const-generic 数据结构的经典示例:方矩阵。 struct Matrix { inner: [[T; N]; N] } 我想返回一个结构体,其 const 参数是动态定义的:
以下代码无法编译,因为 x在移动之后使用(因为 x 具有类型 &mut u8 ,它没有实现 Copy 特性) fn main() { let mut a: u8 = 1; let x:
我在玩 Rust,发现了下面的例子: fn main() { let mut x = [3, 4, 5].to_vec(); x; println!("{:?}", x); }
假设一个 Rust 2018 宏定义了一个 async里面的功能。它将使用的语法与 Rust 2015 不兼容。因此,如果您使用 2015 版编译您的 crate,那么宏中的扩展代码不会与它冲突吗?
假设我有一些 Foo 的自定义集合s: struct Bar {} struct Foo { bar: Bar } struct SubList { contents: Vec, }
代码如下: fn inner(x:&'a i32, _y:&'b i32) -> &'b i32 { x } fn main() { let a = 1; { let b
在lifetime_things的定义中,'b的生命周期比'a长,但实际上当我调用这个函数时,x1比y1长,但是这样可以编译成功: //here you could see 'b:'a means
我正在尝试检索 FLTK-RS Widget 周围的 Arc Mutex 包装器的内部值: pub struct ArcWidget(Arc>); impl ArcWidget{ pub
如下代码所示,我想封装一个定时函数,返回一个闭包的结果和执行时间。 use tap::prelude::Pipe; use std::time::{Instant, Duration}; pub fn
我想实现自己的通用容器,这是我正在使用的特征的片段: pub trait MyVec where Self: Default + Clone + IntoIterator, Self:
所需代码: 注释掉的块可以编译并工作,但是我想从嵌套的匹配样式转变为更简洁的函数链 async fn ws_req_resp(msg: String, conn: PgConn) -> Result>
我正在尝试编写一些代码,该代码将生成具有随机值的随机结构。对于结构,我具有以下特征和帮助程序宏: use rand::{thread_rng, Rng}; use std::fmt; pub trai
我有一个带有函数成员的结构: struct Foo { fun: Box, } type FooI = Foo; 这不起作用: error[E0106]: missing lifetime s
我是一名优秀的程序员,十分优秀!