我昨天写了这些生锈的字。它将27位从32位整数转换为3x9字节数组,但我的直觉是,这应该在没有可变变量ans的情况下完成。
pub fn u32_to_preformated_vector(image:u32) ->[[u8;9];3] {
let mut ans:[[u8; 9]; 3]= [[0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0]];
let image = !image;
for i in 0..27 {
ans[i/9][i%9] = 1 & (image >> i) as u8;
}
ans
}什么才是这里最干净的代码?宏还是迭代器魔法?
发布于 2020-04-16 10:54:57
函数u32_to_preformated_vector的名称让我假设我得到的是我实际得到的东西。所以我认为这个名字可以改进:
在保持可变数组的情况下,我使用了以下代码:
pub fn u32_to_preformatted_array(image: u32) -> [[u8; 9]; 3] {
let mut result = [[0u8; 9]; 3];
let inverted = !image;
for n in 0..3 {
let nonet = inverted >> n * 9;
for m in 0..9 {
result[n][m] = 1 & (nonet >> m) as u8;
}
}
result
}我想如果我将倒置的image绑定到一个新的名称(inverted)上会有帮助。这样,在for循环中,读者可以看到它与作为参数传递给函数的值是不同的。
我还将单个for循环转换为两个嵌套的for循环。虽然嵌套这些循环通常可能会导致性能问题,但在这里它并没有坏处,因为内部代码中的迭代次数保持不变(27)。这样,我认为索引处理比做一个除法和一个余数来计算它们更清楚。它也可能使比特顺序变得更加明显。
数组的初始值可以以更紧凑的方式初始化,因为数组中的所有值都是相同的(本例中为0u8)。
我不认为在函数中有一个可变数组是一件大事。虽然我在很大程度上追求的是不变性,但在这里,变异的可能性是非常有限的。由于这是一个价值得到建造的地方,所以在不同的地方使用它是没有危险的。从返回值的点开始,函数的声明将使其不可变。
我还试图通过使用迭代器来摆脱这个单一的mut。只要将函数的返回类型从数组更改为向量,就很容易:
pub fn u32_to_preformatted_vec(image: u32) -> Vec> {
let inverted = !image;
(0..3)
.map(|i| (inverted >> 9 * i) & 0b111_111_111) // `&` not strictly needed
.map(|nonet| (0..9).map(|i| 1 & (nonet >> i) as u8).collect())
.collect()
}一般来说,我认为在map/reduce样式中工作比在数组上工作要好得多。您也可以将Vec转换为片,但是对数组的转换更困难,而且常常使用像.clone_from_slice()这样的函数来完成,因为这需要一个以前分配的数组,这个数组又是可变的。我还尝试为Vec获取一个切片,然后使用TryFrom特性将其转换为一个数组。当我让它在一维数组中工作时,我没有让它在多维数组[[u8; 9]; 3]中工作。
在设计解决方案时,也很少需要从Vec到数组。Vec只是数组周围的一点代码(这就是为什么可以很容易地从它得到一个片段)。因此,在使用数组时,您不会真正保存任何东西。
考虑到整个问题,我想知道这种转换的原因是什么。您正在释放一个4字节的值,最多可以使用27字节的内存。这样可以增加程序的内存使用量,我不知道你从中得到了什么。我不认为它实际上会提高性能,因为在访问数据时,您会失去局部性。计算机中的缓存将不能像使用原始的4字节值那样工作。
如果您试图从转换中获得的目标是提高可读性,我认为您可能会尝试定义帮助函数来获取(或设置)各个位。计算实际上非常容易,在CPU寄存器中执行,编译器可以内联。那应该相当快,…比将数据转换到这个二维数组更快,这需要大量访问计算机内存,因为它不能在寄存器中完成。
https://codereview.stackexchange.com/questions/240480
复制相似问题