<p>像在 C++ 这样的语言中,又两个不同的运算符来调用方法:<code>.</code>直接在对象上调用方法,而<code>-></code>在一个对象的指针上调用方法,这时需要先解引用(dereference)指针。换句话说,如果<code>object</code>是一个指针,那么<code>object->something()</code>就像<code>(*object).something()</code>一样。</p>
<p>像在 C++ 这样的语言中,有两个不同的运算符来调用方法:<code>.</code>直接在对象上调用方法,而<code>-></code>在一个对象的指针上调用方法,这时需要先解引用(dereference)指针。换句话说,如果<code>object</code>是一个指针,那么<code>object->something()</code>就像<code>(*object).something()</code>一样。</p>
<p>Rust 并没有一个与<code>-></code>等效的运算符;相反,Rust 有一个叫<strong>自动引用和解引用</strong>(<em>automatic referencing and dereferencing</em>)的功能。方法调用是 Rust 中少数几个拥有这种行为的地方。</p>
<p>让我们通过一用代码来表现的场景,来看看为什么这里枚举是有用的而且比结构体更合适。比如我们要处理 IP 地。目前被广泛使用的两个主要 IP 标准:IPv4(version four)和 IPv6(version six)。这是我们的程序只可能会遇到两种 IP 地址:所以可以<strong>枚举</strong>出所有可能的值,这也正是它名字的由来。</p>
<p>让我们通过一用代码来表现的场景,来看看为什么这里枚举是有用的而且比结构体更合适。比如我们要处理 IP 地址。目前被广泛使用的两个主要 IP 标准:IPv4(version four)和 IPv6(version six)。这是我们的程序只可能会遇到两种 IP 地址:所以可以<strong>枚举</strong>出所有可能的值,这也正是它名字的由来。</p>
<p>任何一个 IP 地址要么是 IPv4 的要么是 IPv6 的而不能两者都是。IP 地址的这个特性使得枚举数据结构非常适合这个场景,因为枚举值只可能是其中一个成员。IPv4 和 IPv6 从根本上讲仍是 IP 地址,所以当代码在处理申请任何类型的 IP 地址的场景时应该把他们当作相同的类型。</p>
<p>可以通过在代码中定义一个<code>IpAddrKind</code>枚举来表现这个概念并列出可能的 IP 地址类型,<code>V4</code>和<code>V6</code>。这被称为枚举的<strong>成员</strong>(<em>variants</em>):</p>
<p>让我们如何通过传递拥有不同具体生命周期的引用来观察他们是如何限制<code>longest</code>函数的使用的。列表 10-22 是一个应该在任何编程语言中都很直观的例子:<code>string1</code>直到外部作用域结束都是有效的,<code>string2</code>则在内部作用域中是有效的,而<code>result</code>则引用了一些直到外部作用域结束都是有效的值。借用检查器赞同这些代码;它能够编译和运行,并打印出<code>The longest string is long string is long</code>:</p>
<p>让我们如何通过传递拥有不同具体生命周期的引用来观察他们是如何限制<code>longest</code>函数的使用的。列表 10-22 是一个应该在任何编程语言中都很直观的例子:<code>string1</code>直到外部作用域结束都是有效的,<code>string2</code>则在内部作用域中是有效的,而<code>result</code>则引用了一些直到内部作用域结束都是有效的值。借用检查器赞同这些代码;它能够编译和运行,并打印出<code>The longest string is long string is long</code>:</p>
<p>对于引用,可以使用<code>&</code>和<code>&mut</code>语法来分别创建不可变和可变的引用。不过对于<code>RefCell<T></code>,我们使用<code>borrow</code>和<code>borrow_mut</code>方法,它是<code>RefCell<T></code>拥有的安全 API 的一部分。<code>borrow</code>返回<code>Ref</code>类型的智能指针,而<code>borrow_mut</code>返回<code>RefMut</code>类型的智能指针。这两个类型实现了<code>Deref</code>所以可以被当作常规引用处理。<code>Ref</code>和<code>RefMut</code>动态的借用所有权,而他们的<code>Drop</code>实现也动态的释放借用。</p>
<p>编程语言有一些不同的方法来实现线程。很多操作系统提供了创建新线程的 API。另外,很多编程语言提供了自己的特殊的线程实现。编程语言提供的线程有时被称作<strong>轻量级</strong>(<em>lightweight</em>)或<strong>绿色</strong>(<em>green</em>)线程。这些语言将一系列绿色线程放入不同数量的操作系统线程中执行。因为这个原因,语言调用操作系统 API 创建线程的模型有时被称为 <em>1:1</em>,一个 OS 线程对应一个语言线程。绿色线程模型被称为 <em>M:N</em> 模型,<code>M</code>个绿色线程对应<code>N</code>个 OS 线程,这里<code>M</code>和<code>N</code>不必相同。</p>
<p>每一个模型都有其自己的优势和取舍。对于 Rust 来说最重要的取舍是运行时支持。<strong>运行时</strong>是一个令人迷惑的概念;在不同上下文中它可能有不同的含义。这里其代表二进制文件中包含的语言自身的代码。对于一些语言,这些代码是庞大的,另一些则很小。通俗的说,“没有运行时”通常被人们用来指代“小运行时”,因为任何非汇编语言都存在一定数量的运行时。更小的运行时拥有更少的功能不过其优势在于更小的二进制输出。更小的二进制文件更容易在更多上下文中与其他语言结合。虽然很多语言觉得增加运行时来换取更多功能没有什么问题,但是 Rust 需要做到几乎没有运行时,同时不能在为了维持性能而能够在 C 语言中调用方面做出妥协。</p>
<p>哇哦,太长不看!需要指出一些重要的部分:第一个提示表明<code>Rc<Mutex<i32>></code>不能安全的在线程间传递。理由也在错误信息中,经过提取之后,表明“不满足<code>Send</code> trait bound”(<code>the trait bound Send is not satisfied</code>)。下一部分将会讨论<code>Send</code>,它是一个确保确保用于线程的类型是适合并发环境的 trait。</p>
<p>回到之前的例子:<code>Arc<T></code>和<code>Rc<T></code>除了<code>Arc<T></code>内部的原子性之外他们是等价的。其 API 也是一样的,所以可以修改<code>use</code>行和<code>new</code>调用。列表 16-15 中的代码最终可以编译和运行:</p>
<p>哇哦,太长不看!说重点:第一个提示表明 <code>Rc<Mutex<i32>></code>不能安全的在线程间传递。理由也在错误信息中,“不满足<code>Send</code> trait bound”(<code>the trait bound Send is not satisfied</code>)。下一部分将会讨论<code>Send</code>,它是确保许多用在多线程中的类型,能够适合并发环境的 trait 之一。</p>
<p>回到之前的例子:<code>Arc<T></code>和<code>Rc<T></code>除了<code>Arc<T></code>内部的原子性之外没有区别。其 API 也相同,所以可以修改<code>use</code>行和<code>new</code>调用。列表 16-15 中的代码最终可以编译和运行:</p>
<p>因为<code>Rc<T></code>没有标记为<code>Send</code>,Rust 的类型系统和 trait bound 会确保我们永远也不会忘记或错误的把一个<code>Rc<T></code>值不安全的在线程间传递。列表 16-14 曾尝试这么做,不过得到了一个错误说<code>the trait Send is not implemented for Rc<Mutex<i32>></code>。当切换为标记为<code>Send</code>的<code>Arc<T></code>时,代码就可以编译了。</p>
<p>因为<code>Rc<T></code>没有标记为<code>Send</code>,Rust 的类型系统和 trait bound 会确保我们不会错误的把一个<code>Rc<T></code>值不安全的在线程间传递。列表 16-14 曾尝试这么做,不过得到了一个错误,<code>the trait Send is not implemented for Rc<Mutex<i32>></code>。当切换为标记为<code>Send</code>的<code>Arc<T></code>时,就没有问题了。</p>
让我们如何通过传递拥有不同具体生命周期的引用来观察他们是如何限制`longest`函数的使用的。列表 10-22 是一个应该在任何编程语言中都很直观的例子:`string1`直到外部作用域结束都是有效的,`string2`则在内部作用域中是有效的,而`result`则引用了一些直到外部作用域结束都是有效的值。借用检查器赞同这些代码;它能够编译和运行,并打印出`The longest string is long string is long`:
让我们如何通过传递拥有不同具体生命周期的引用来观察他们是如何限制`longest`函数的使用的。列表 10-22 是一个应该在任何编程语言中都很直观的例子:`string1`直到外部作用域结束都是有效的,`string2`则在内部作用域中是有效的,而`result`则引用了一些直到内部作用域结束都是有效的值。借用检查器赞同这些代码;它能够编译和运行,并打印出`The longest string is long string is long`: