【问题标题】:Explicit annotations of references vs values in rustrust 中引用与值的显式注释
【发布时间】:2019-04-29 17:04:10
【问题描述】:

所以在 Rust 中,我对值与引用的类型推断能力感到困惑。例如,

fn main() {
    let s1 = String::from("h1");
    let s2 = &s1;
    println!("string is {}", s1);
} 

借用检查器允许编译,但我不知道为什么? s2 这里是一个值还是被推断为对 s1 的引用?

在 C++ 中,通过引用初始化新值会创建一个副本,除非该变量被显式声明为引用:

#include <string>

int main(int argc, char const* argv[]) {
    std::string s1("Hello");
    std::string& s2 = s1; // reference
    std::string s3 = s2; // copy
}

所以在 rust 中,我的问题是,类型推断是否也适用于引用与值的情况?如果是这样,什么时候需要将变量显式声明为引用?

【问题讨论】:

  • 从类型检查器的角度来看,结构值和对结构值的引用是两种不同的类型。这可能是让你失望的原因吗?
  • 在 rust 示例中,s2 是推断为引用还是从引用创建的新值?
  • &amp;s1 表示你有一个引用类型。
  • 我明白了,因此不需要在 let 端显式声明。现在明白了。
  • 要澄清的另一件事是,Rust 通常移动值而不是复制它们。如果您要在 Rust 示例中添加一行 let s3 = s1,例如 this,那么它将无法编译,因为该值已从 s1 移出并移至 s3Clone 特征可用于显式创建值的新副本(例如 let s3 = s1.clone()),Copy 特征可用于允许隐式逐位复制(例如 i32 等原语)。

标签: rust


【解决方案1】:

我的类型是什么?

s2 的类型是&amp;std::string::String,更常用的简单表示为&amp;String

s2 是以(只读)引用(&amp;)的形式借用s1,并且会阻止s1 在@987654330 时被写入(如果它是可变的) @ 在范围内。

我以后如何自行确定?

Sample code on Playground

如果您想要求编译器显示特定绑定的类型,一个常见的习惯用法是使用let () = some_binding;。编译器会给你一个错误,显示some_binding的类型。

我注意到编译器似乎通过省略前导 &amp; 来“提供帮助”,因此当您熟悉 Rust 时,我建议您尝试调用具有错误类型的虚拟函数,这会显示绑定的完整类型。在这里,编译器确实显示了调用参数的完整类型,您可以看到它是&amp;String

显式声明类型(针对 OP 的评论):

关于在声明的 let 一侧显式声明类型,如在 C++ (see 'AAA') 中,Rust 支持类似的东西:

let a: u32 = 42;

// equvialent
let b = 42_u32;

对于构造类型,类型将是类型构造函数返回的任何类型:

// seems somewhat redundant (since `String::new()` returns `String`) 
// but is perfectly legal
let c: String = String::new("Hello, world!");

// equivalent
let d = String::new("Hello, world!");

所以只要编译器可以从右侧明确确定类型,就可以推断出let的类型。

注意:const 绑定的类型规范仍然是强制性的:

// error: despite the explicit type declaration on the RHS, the type is still required
//const foo = 42_u32;

// since the type must be explicitly defined specifying again on the RHS is redundant
// (but legal):
const foo: u32 = 42_u32;

// Rustic (idiomatic) for `const`
const bar: u32 = 42;

【讨论】:

  • 另外需要考虑的一点:Rust 进行的隐式类型转换比 C++ 少得多,因此 OP 的 C++ 示例(复制模式)中第三行的直接翻译是 let s3: String = s2; 并且不会编译.它需要显式调用s2.to_string()
猜你喜欢
  • 1970-01-01
  • 2016-10-11
  • 2018-11-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多