Rust中的num包提供了一种通过T::zero()
和T::one()
表示零和一的方法。有没有办法表示其他整数,比如两个,三个等?
考虑以下(人为)示例:
extern crate num;
trait IsTwo {
fn is_two(self) -> bool;
}
impl<T: num::Integer> IsTwo for T {
fn is_two(self) -> bool {
self == (T::one() + T::one())
}
}
是否有更好的方式将T::one() + T::one()
表示为2
?
答案 0 :(得分:1)
在通用代码中表示任意整数的一种方法是使用num::NumCast
特征:
impl<T: num::Integer + num::NumCast> IsTwo for T {
fn is_two(self) -> bool {
self == T::from(2).unwrap()
}
}
相关方法是使用num::FromPrimitive
特征:
impl<T: num::Integer + num::FromPrimitive> IsTwo for T {
fn is_two(self) -> bool {
self == T::from_i32(2).unwrap()
}
}
答案 1 :(得分:1)
你可以写一个函数:
Sub CommandButton1_Click()
Dim day_a, day_b As Date, point As String, east_a, north_a, height_a, height_b, east_b, north_b As Double
Dim i1, i2, i3, i4, i5, i6, i7 As Variant
i1 = 1: i2 = 1
Worksheets("INPUT").Cells(i1, i2).Select
Do While Not IsEmpty(ActiveCell)
Worksheets("INPUT").Cells(i1, i2).Activate
If ActiveCell.Value = "Id" Then
i3 = Split(ActiveCell.Address(columnAbsolute:=True, ReferenceStyle:=xlR1C1), "C")(1)
MsgBox (cellidrow)
ElseIf ActiveCell.Value = "Nord" Then
i4 = Split(ActiveCell.Address(columnAbsolute:=True, ReferenceStyle:=xlR1C1), "C")(1)
ElseIf ActiveCell.Value = "Øst" Then
i5 = Split(ActiveCell.Address(columnAbsolute:=True, ReferenceStyle:=xlR1C1), "C")(1)
ElseIf ActiveCell.Value = "S_OBJID" Then
i6 = Split(ActiveCell.Address(columnAbsolute:=True, ReferenceStyle:=xlR1C1), "C")(1)
ElseIf ActiveCell.Value = "DATO" Then
i7 = Split(ActiveCell.Address(columnAbsolute:=True, ReferenceStyle:=xlR1C1), "C")(1)
Else
End If
i2 = i2 + 1
Loop
MsgBox (i3 & i4 & i5 & i6 & i7)
Sheets("INPUT").Cells(i5, i3).Select
MsgBox (ActiveCell.Value)
End Sub
我之所以选择这种形式是因为它很容易被制作成一个宏,可以重复用于任何一组值:
fn two<T>() -> T
where T: num::Integer,
{
let mut v = T::zero();
for _ in 0..2 {
v = v + T::one();
}
v
}
我现在听到了担忧......“但这是一个循环而且效率低下!”这就是优化编译器的用途。在发布模式下编译时,这是num_constant!(two, 2);
num_constant!(forty_two, 42);
的LLVM IR:
two
这是对的 - 它已被优化为值; Function Attrs: noinline readnone uwtable
define internal fastcc i32 @_ZN10playground3two17hbef99995c3606e93E() unnamed_addr #3 personality i32 (i32, i32, i64, %"unwind::libunwind::_Unwind_Exception"*, %"unwind::libunwind::_Unwind_Context"*)* @rust_eh_personality {
bb3:
br label %bb8
bb8: ; preds = %bb3
ret i32 2
}
。没有循环。
答案 2 :(得分:1)
从0和1伪造任何数字相对简单:
算法很简单:
fn convert<T: Integer>(n: usize) -> T {
let two = T::one() + T::one();
let mut n = n;
let mut acc = T::one();
let mut result = T::zero();
while n > 0 {
if n % 2 != 0 {
result += acc;
}
acc *= two;
n /= 2;
}
result
}
在Debug(O(log2(N))迭代)和Release(编译器完全优化)中都会很有效。
对于那些希望在行动中看到它的人here on the playground,我们可以看到convert::<i32>(12345)
已按预期优化为12345
。
作为对读者的练习,实现convert
的通用版本,其中包含任何Integer
参数,毕竟n
上的操作不多。