# Peek

有一件事我们上次甚至没有去做，那就是 peek。我们开始吧，我们需要做的就是返回对列表头元素的引用（如果它存在的话）。听起来很简单，让我们试试：

```rust
pub fn peek(&self) -> Option<&T> {
    self.head.map(|node| {
        &node.elem
    })
}
```

```rust
> cargo build

error[E0515]: cannot return reference to local data `node.elem`
  --> src/second.rs:37:13
   |
37 |             &node.elem
   |             ^^^^^^^^^^ returns a reference to data owned by the current function

error[E0507]: cannot move out of borrowed content
  --> src/second.rs:36:9
   |
36 |         self.head.map(|node| {
   |         ^^^^^^^^^ cannot move out of borrowed content


```

叹。 Rust，现在怎么办？

map按值获取self，这会将Option从它所在的对象中移出。以前这是好的，因为我们刚刚把它拿出来，但现在我们真的想把它留在原来的地方。正确的处理方法是使用 Option 上的 as\_ref 方法，它有以下定义：

```rust
impl<T> Option<T> {
    pub fn as_ref(&self) -> Option<&T>;
}
```

它将 Option 降级为对其内部的引用。我们可以自己用一个显式的匹配来完成，但是不可以。这确实意味着我们需要做一个额外的解引用来切断额外的间接寻址，但谢天谢地，operator 为我们处理。

```rust
pub fn peek(&self) -> Option<&T> {
    self.head.as_ref().map(|node| {
        &node.elem
    })
}
```

```rust
cargo build

    Finished dev [unoptimized + debuginfo] target(s) in 0.32s
```

搞定了。

我们也可以使用 as\_mut 创建一个可变的版本：

```rust
pub fn peek_mut(&mut self) -> Option<&mut T> {
    self.head.as_mut().map(|node| {
        &mut node.elem
    })
}
```

```rust
lists::cargo build
```

别忘了测试一下：

```rust
#[test]
fn peek() {
    let mut list = List::new();
    assert_eq!(list.peek(), None);
    assert_eq!(list.peek_mut(), None);
    list.push(1); list.push(2); list.push(3);

    assert_eq!(list.peek(), Some(&3));
    assert_eq!(list.peek_mut(), Some(&mut 3));
}
```

```rust
cargo test

     Running target/debug/lists-5c71138492ad4b4a

running 3 tests
test first::test::basics ... ok
test second::test::basics ... ok
test second::test::peek ... ok

test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured
```

这很好，但是我们并没有真正的测试看看我们是否可以改变peek\_mut的返回值，是吗？如果一个引用是可变的，但是没有人对它进行变异，那么我们真的测试过它的可变性吗？让我们试着在这个选项上使用map，在以下位置输入一个深刻的值：

```rust
#[test]
fn peek() {
    let mut list = List::new();
    assert_eq!(list.peek(), None);
    assert_eq!(list.peek_mut(), None);
    list.push(1); list.push(2); list.push(3);

    assert_eq!(list.peek(), Some(&3));
    assert_eq!(list.peek_mut(), Some(&mut 3));
    list.peek_mut().map(|&mut value| {
        value = 42
    });

    assert_eq!(list.peek(), Some(&42));
    assert_eq!(list.pop(), Some(42));
}
```

```rust
> cargo test

error[E0384]: cannot assign twice to immutable variable `value`
   --> src/second.rs:100:13
    |
99  |         list.peek_mut().map(|&mut value| {
    |                                   -----
    |                                   |
    |                                   first assignment to `value`
    |                                   help: make this binding mutable: `mut value`
100 |             value = 42
    |             ^^^^^^^^^^ cannot assign twice to immutable variable          ^~~~~
```

编译器抱怨值是不可变的，但是我们很清楚地写下了\&mut value；给出了什么？事实证明，以这种方式编写闭包的参数并没有指定值是可变引用。相反，它会创建一个模式，该模式将与闭包的参数相匹配；|\&mut value |意味着“参数是一个可变的引用，但是请将它指向的值复制到value中”。如果我们只使用 |value |，那么值的类型将是\&mut i32，我们实际上可以改变head：

```rust
#[test]
fn peek() {
    let mut list = List::new();
    assert_eq!(list.peek(), None);
    assert_eq!(list.peek_mut(), None);
    list.push(1); list.push(2); list.push(3);

    assert_eq!(list.peek(), Some(&3));
    assert_eq!(list.peek_mut(), Some(&mut 3));

    list.peek_mut().map(|value| {
        *value = 42
    });

    assert_eq!(list.peek(), Some(&42));
    assert_eq!(list.pop(), Some(42));
}
```

```rust
cargo test

     Running target/debug/lists-5c71138492ad4b4a

running 3 tests
test first::test::basics ... ok
test second::test::basics ... ok
test second::test::peek ... ok

test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured
```

好多了！


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://chapin666.gitbook.io/too-many-list-zh/yi-ge-hai-hang-de-dan-lian-zhan/peek.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
