refパターン(@Rust)

https://doc.rust-jp.rs/rust-by-example-ja/custom_types/enum/testcase_linked_list.html

のコードでrefと&で何が違うのと思ったのですが、

Rust by exampleの以下のページに出てくるrefパターン

https://doc.rust-jp.rs/rust-by-example-ja/scope/borrow/ref.html

の解説は、

—————————-

 // 左辺に`ref`をつけることによる借用と、右辺に`&`をつけることによる借用は等価

    let ref ref_c1 = c;

    let ref_c2 = &c;


ということなので、どちらも借用ですが似てるようで意味は全く異なります。

該当部分のコード全体をいかに再掲(長ったらしいので日本語は削除)しますが、タプル全体の文字列と長さの取得処理は再帰処理を使っています。

https://doc.rust-jp.rs/rust-by-example-ja/custom_types/enum/testcase_linked_list.html

use crate::List::*; // equivalent to following two lines, it's a short form of the enum List 
//use crate::List::Cons;
//use crate::List::Nil;

#[derive(Debug)]
enum List {
    // Cons: Tuple struct that wraps an element and a pointer to the next node
    Cons(u32, Box 	 	 	),
    // Nil: A node that signifies the end of the linked list
    Nil,
}

// Methods can be attached to an enum
impl List {
    // Create an empty list
    fn new() -> List {
        // `Nil` has type `List`
        Nil
    }

    // Consume a list, and return the same list with a new element at its front
    fn prepend(self, elem: u32) -> List {
        // `Cons` also has type List
        Cons(elem, Box::new(self))
    }

    // Return the length of the list(using recursive call)
    fn len(&self) -> u32 {
        // `self` has to be matched, because the behavior of this method
        // depends on the variant of `self`
        // `self` has type `&List`, and `*self` has type `List`, matching on a
        // concrete type `T` is preferred over a match on a reference `&T`
        // after Rust 2018 you can use self here and tail (with no ref) below as well,
        // rust will infer &s and ref tail. 
        // See https://doc.rust-lang.org/edition-guide/rust-2018/ownership-and-lifetimes/default-match-bindings.html
        match *self {
            // Can't take ownership of the tail, because `self` is borrowed;
            // instead take a reference to the tail
            Cons(_, ref tail) => 1 + tail.len(),
            // Base Case: An empty list has zero length
            Nil => 0
        }
    }

    // Return representation of the list as a (heap allocated) string(using recursive call)
    fn stringify(&self) -> String {
        match *self {
            Cons(head, ref tail) => {
                // `format!` is similar to `print!`, but returns a heap
                // allocated string instead of printing to the console
                //println!("st: {}, {}", head, tail.stringify());
                let ret: String = format!("{}, {}", head, tail.stringify());
                println!("{:?}", ret);
                ret
            },
            Nil => {
                format!("Nil")
            },
        }
    }
}

fn main() {
    // Create an empty linked list
    let mut list = List::new();

    // Prepend some elements
    list = list.prepend(1);
    list = list.prepend(2);
    list = list.prepend(3);

    // Show the final state of the list
    println!("linked list has length: {}", list.len());
    println!("{}", list.stringify());
}

コメントにあるように2018年版のRustからは*selfとref tailの*とrefは不要になった(&とrefを推論する)そうで、確かにそう変えてもコンパイルは通ります。となると、fn stringify(&self)も同じように書き換え可能なので、このソースでrefを使う必要はなくなりますが。

        match self {
            // Can't take ownership of the tail, because `self` is borrowed;
            // instead take a reference to the tail
            Cons(_, tail) => 1 + tail.len(),
            // Base Case: An empty list has zero length

 

admin

カテゴリーRust