【问题标题】:How could rust multiply &i32 with i32?rust 如何将 &i32 与 i32 相乘?
【发布时间】:2019-08-31 16:24:28
【问题描述】:

考虑这个例子:

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 不能与&amp;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`

但是当我将浮点数更改为 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);
}

编译器是否实现了&amp;i32i32之间的操作? 如果是,那么在这种类型安全的语言中,这个操作如何证明是合理的?

【问题讨论】:

    标签: rust


    【解决方案1】:

    编译器是否实现了&amp;i32i32之间的操作?

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

    如果是,那么在这种类型安全的语言中,这个操作如何证明是合理的?

    “类型安全”不是布尔属性,而是一个频谱。大多数 C++ 程序员会说 C++ 是类型安全的。然而,C++ 有许多在类型之间自动转换的特性(构造函数,operator T,获取值的引用,...)。在设计一种编程语言时,必须平衡错误的风险(引入方便的类型转换时)和不便(没有它们时)。

    作为一个极端的例子:考虑Option&lt;T&gt; 是否会引用T,如果它是None 则恐慌。这是大多数具有null 的语言的行为。我认为很明显,这个“功能”导致了现实世界中的许多错误(搜索词“十亿美元的错误”)。另一方面,让我们考虑一下编译&amp;i32 * i32 会导致哪些错误。老实说,我什么都想不出来。 Maaaybe 有人想将一个值的原始指针与一个整数相乘吗?在 Rust 中不太可能。所以由于这个特性引入bug的几率很低,但是很方便,所以决定实现。

    这始终是设计师必须平衡的事情。不同的语言在这个范围内处于不同的位置。 Rust 可能被认为比 C++“更类型安全”,但毫无疑问,甚至还有比 Rust 更“类型安全”的语言。在这种情况下,“更安全”只是意味着:决策更倾向于“不便而不是潜在的错误”。

    【讨论】:

      【解决方案2】:

      我认为您可能会将来自 rust 的 &amp;i32 与来自 C 的 &amp;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”的地址。

      然而,在 rust 中,'&' 运算符借用了变量 var。

      在 Rust 中,

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

      这是可行的,因为&amp;var 指的是5,而不是var 的地址。请注意,在 C 中,&amp; 是一个运算符。在 Rust 中,&amp; 充当变量类型的一部分。因此,类型为&amp;i32

      这很令人困惑。如果标准键盘上还有更多字符,我相信设计师会使用不同的。

      请查看book 并仔细按照图表进行操作。书中的例子使用了String,它是在堆上分配的。像i32 这样的原语通常分配在堆栈上,并且可能会被编译器完全优化掉。此外,即使使用引用表示法,原语也经常被复制,因此会让人感到困惑。不过,我认为首先使用 String 查看堆示例会更容易,然后再考虑如何将其应用于原语。逻辑是一样的,但实际的存储和优化可能会有所不同。

      【讨论】:

      • C 肯定不会让您将指针乘以整数。
      • 是的,除非我添加演员表,否则 GCC 会对该代码抛出错误:int var = 5; int newvar = (int) &amp;var * 4;
      【解决方案3】:

      其实很简单:Rust 会自动为你解引用。它不像 C 语言,你必须自己取消引用一个指针。在这方面,Rust 引用与 C++ 引用非常相似。

      【讨论】:

      • 这并非普遍适用。在某些情况下,引用实际上是自动取消引用的;在其他一些情况下,它不是由语言完成的,而是由库功能完成的(比如引用类型的 impl);在其他情况下,引用不会自动取消引用。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-04-23
      • 2022-07-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多