锈如何将i32与&i32相乘?

时间:2019-08-31 16:24:28

标签: rust

考虑以下示例:

fn main() {
    let v: Vec<i32> = vec![1, 2, 3, 4, 5];
    let b: i32 = (&v[2]) * 4.0;
    println!("product of third value with 4 is {}", b);
}

此操作失败,因为无法将float&i32相乘。

error[E0277]: cannot multiply `{float}` to `&i32`
 --> src\main.rs:3:23
  |
3 |   let b: i32 = (&v[2]) * 4.0;
  |                        ^ no implementation for `&i32 * {float}`
  |
  = help: the trait `std::ops::Mul<{float}>` is not implemented for `&i32`

但是当我将float更改为int时,它可以正常工作。

fn main() {
    let v: Vec<i32> = vec![1, 2, 3, 4, 5];
    let b: i32 = (&v[2]) * 4;
    println!("product of third value with 4 is {}", b);
}

编译器是否在&i32i32之间实现了操作? 如果是,该操作如何以这种类型安全的语言来证明?

3 个答案:

答案 0 :(得分:10)

  

编译器是否在&i32i32之间实现了操作?

是的。好吧,不是编译器,而是标准库。您可以看到提示in the documentation

  

如果是,那么如何使用这种类型安全的语言来证明此操作的合理性?

“类型安全”不是布尔属性,而是频谱。大多数C ++程序员会说C ++是类型安全的。但是,C ++具有许多自动在类型之间进行转换的功能(构造函数,operator T,使用值的引用,...)。在设计编程语言时,必须权衡错误的风险(引入方便的类型转换时)与不便(如果没有缺陷时)。

举一个极端的例子:考虑Option<T>是否会取消引用T并在None时惊慌。这就是大多数使用null的语言的行为。我认为很明显,这种“功能”导致了现实世界中的许多错误(搜索术语“十亿美元的错误”)。另一方面,让我们考虑使用&i32 * i32进行编译可能导致哪些错误。老实说我没有想到。 Maaaybe 有人想将一个值的原始指针与整数相乘吗?在Rust中不太可能。因此,由于引入带有此功能的错误的机会很小,但是很方便,因此决定实施该功能。

这始终是设计师必须平衡的东西。在此频谱上,不同的语言处于不同的位置。 Rust可能被认为比C ++更具“类型安全”,但毫无疑问,甚至还有比Rust更“类型安全”的语言。在这种情况下,“更安全的类型”仅表示:决策更倾向于“不便而不是潜在的错误”。

答案 1 :(得分:2)

我认为您可能会将锈迹中的'&i32'与C语言中的&var混淆。

在C中,

int var = 5;
int newvar = &var * 4;  /* this would be bad code, 
                           should not multiply an address by an integer!
                           Of course, C will let you. */

“&”运算符返回变量“ var”的地址。

但是,在锈病中,“&”运算符借用了变量var。

在Rust中,

var: i32 = 5;
assert!(&var * 8, 40);

这有效,因为&var是5,而不是var的地址。请注意,在C中,“&”是运算符。在Rust中,“&”充当变量类型的一部分。因此,类型为&i32。

这非常令人困惑。如果标准键盘上还有更多字符,我相信设计师会使用其他键盘。

请参阅book,并仔细按照图示进行操作。本书中的示例使用String,它在堆上分配。像i32这样的基元通常在堆上分配,并且可以由编译器完全优化。另外,即使使用引用符号时也会频繁地复制基元,从而造成混乱。尽管如此,我认为先使用String查看堆示例,然后再考虑如何将其应用于基元会更容易。逻辑是相同的,但是实际的存储和优化可能有所不同。

答案 2 :(得分:-1)

实际上非常简单:Rust会自动为您取消引用参考。不同于C,您必须自己取消引用指针。在这方面,Rust引用与C ++引用非常相似。