Rustのmutと&mutと&
rust
Lastmod: 2023-06-23

関数の引数宣言における、無印とmut&mut&の意味と使いどころをまとめる。

無印

所有権が関数に移動する。以上。

fn main() {
    let s = String::from("hello");

    takes_ownership(s);

}

fn takes_ownership(some_string: String) {
    println!("{}", some_string);
}

&

所有権は移動しない。Readだけ可能、なはず。

fn main() {
    let s = String::from("hello");

    let len = calculate_length(&s);
}

fn calculate_length(s: &String) -> usize {
    s.len()
}

&mut

所有権が一時的に移動する。Write可能。

fn main() {
    let mut s = String::from("hello");

    change(&mut s);
}

fn change(some_string: &mut String) {
    some_string.push_str(", world");
}

mut

所有権が関数に移動する。無印との違いは関数内で引数がmutとして扱えること。

fn main() {
    let listener = TcpListener::bind("127.0.0.1:8090").unwrap();

    for stream in listener.incoming() {
        let stream = stream.unwrap();

        handle_connection(stream);
    }
}

fn handle_connection(mut stream: TcpStream) {
    let buf_reader = BufReader::new(&mut stream);
    let http_request: Vec<_> = buf_reader
        .lines()
        .map(|result| result.unwrap())
        .take_while(|line| !line.is_empty())
        .collect();

    println!("Request: {:#?}", http_request);
}

ここでfn handle_connection(mut stream: TcpStream)の宣言をfn handle_connection(stream: TcpStream)と変えると

$ cargo run
   Compiling todo-rust v0.1.0 (/home/coder/todo-rust)
error[E0596]: cannot borrow `stream` as mutable, as it is not declared as mutable
  --> src/main.rs:17:37
   |
17 |     let buf_reader = BufReader::new(&mut stream);
   |                                     ^^^^^^^^^^^ cannot borrow as mutable
   |
help: consider changing this to be mutable
   |
16 | fn handle_connection(mut stream: TcpStream) {
   |                      +++

For more information about this error, try `rustc --explain E0596`.
error: could not compile `todo-rust` due to previous error

下記のようにlet mut stream = stream;と、関数内でmutとして再宣言すると問題なく進む。

fn handle_connection(stream: TcpStream) {
    let mut stream = stream;
    let buf_reader = BufReader::new(&mut stream);
    let http_request: Vec<_> = buf_reader
        .lines()
        .map(|result| result.unwrap())
        .take_while(|line| !line.is_empty())
        .collect();

    println!("Request: {:#?}", http_request);
}

やってることは同じだと思われる。