Open10

cannot return value referencing local data

botamotchbotamotch
X cargo run rhb.json 'Slide (5).png'
   Compiling test-app01 v0.1.0 (/home/botamotch/Git/botamotch/Rust/test-app01)
error[E0515]: cannot return value referencing local data `sheet.cells`
  --> src/main.rs:56:5
   |
44 |       let cell: &Cell = sheet
   |  _______________________-
45 | |         .cells
46 | |         .get(framename)
   | |_______________________- `sheet.cells` is borrowed here
...
56 |       Ok(&cell)
   |       ^^^^^^^^^ returns a value referencing data owned by the current function

For more information about this error, try `rustc --explain E0515`.
error: could not compile `test-app01` (bin "test-app01") due to previous error
botamotchbotamotch

ローカルデータを参照している値を返すことはできません

関数が所有するデータを参照する値を返しています

的な

botamotchbotamotch

こんなコードで

#[derive(Deserialize, Clone)]
pub struct Sheet {
    frames: HashMap<String, Cell>,
}

#[derive(Deserialize, Clone)]
struct Cell {
    frame: RectSheet,
}

impl Cell {
    fn copy(&self) -> Cell {
        Cell {
            frame: RectSheet {
                x: self.frame.x,
                y: self.frame.y,
                w: self.frame.w,
                h: self.frame.h,
            },
        }
    }
}

fn bar<'a>(filename: &'a str, framename: &'a str) -> Result<&'a Cell> {
    let mut file = std::fs::File::open(filename).map_err(|e| anyhow!(e))?;
    let mut s = String::new();
    file.read_to_string(&mut s).map_err(|e| anyhow!(e))?;
    let sheet: Sheet = serde_json::from_str(&s).map_err(|e| anyhow!(e))?;
    let cell: &Cell = sheet
        .frames
        .get(framename)
        .ok_or_else(|| anyhow!("frame not found"))?;

    Ok(cell)
}

こんな感じのエラーが出る

X cargo run rhb.json 'Slide (5).png'
   Compiling test-app01 v0.1.0 (/home/botamotch/Git/botamotch/Rust/test-app01)
error[E0515]: cannot return value referencing local data `sheet.frames`
  --> src/main.rs:86:5
   |
81 |       let cell: &Cell = sheet
   |  _______________________-
82 | |         .frames
83 | |         .get(framename)
   | |_______________________- `sheet.frames` is borrowed here
...
86 |       Ok(cell)
   |       ^^^^^^^^ returns a value referencing data owned by the current function

For more information about this error, try `rustc --explain E0515`.
error: could not compile `test-app01` (bin "test-app01") due to previous error
botamotchbotamotch

コピーを作る関数を実装してエラーは回避した。多コピーの現在を読め

impl Cell {
    fn copy(&self) -> Cell {
        Cell {
            frame: RectSheet {
                x: self.frame.x,
                y: self.frame.y,
                w: self.frame.w,
                h: self.frame.h,
            },
        }
    }
}

fn foo(filename: &str, framename: &str) -> Result<Cell> {
    let mut file = std::fs::File::open(filename).map_err(|e| anyhow!(e))?;
    let mut s = String::new();
    file.read_to_string(&mut s).map_err(|e| anyhow!(e))?;
    let sheet: Sheet = serde_json::from_str(&s).map_err(|e| anyhow!(e))?;

    Ok(sheet
        .frames
        .get(framename)
        .ok_or_else(|| anyhow!("frame not found"))?
        .copy())
}
botamotchbotamotch

まさにこれじゃん。草

fn main() {
    {
        let r;
        {
            let x = 5;
            r = &x;
        }
        println!("r: {}", r);
    }
}
botamotchbotamotch
$ cargo run
   Compiling chapter10 v0.1.0 (file:///projects/chapter10)
error[E0515]: cannot return value referencing local variable `result`
(エラー[E0515]: ローカル変数`result`を参照している値は返せません)
  --> src/main.rs:11:5
   |
11 |     result.as_str()
   |     ------^^^^^^^^^
   |     |
   |     returns a value referencing data owned by the current function
   |     `result` is borrowed here
   |    (現在の関数に所有されているデータを参照する値を返しています
   |     `result`はここで借用されています)

error: aborting due to previous error

For more information about this error, try `rustc --explain E0515`.
error: could not compile `chapter10`.

To learn more, run the command again with --verbose.

ダングリング参照を変えてくれるようなライフタイム引数を指定する手段はなく、 コンパイラは、ダングリング参照を生成させてくれません。今回の場合、最善の修正案は、 (呼び出し先ではなく)呼び出し元の関数に値の片付けをさせるために、参照ではなく所有されたデータ型を返すことでしょう。

botamotchbotamotch

もしかしたらコピーメソッドを実装して解決する方法は最善だったのかもしれない

botamotchbotamotch

参照を使用する関数や構造体にはライフタイム引数を指定する必要がある。

にもかかわらずこのコードはコンパイル可能。予測可能なケースではライフタイムが省略可能なときもある。

fn first_word(s: &str) -> &str {
    let bytes = s.as_bytes();

    for (i, &item) in bytes.iter().enumerate() {
        if item == b' ' {
            return &s[0..i];
        }
    }

    &s[..]
}

これと同じ

fn first_word<'a>(s: &'a str) -> &'a str {
botamotchbotamotch

これがわかればジェネリックな型引数、トレイト境界、ライフタイム指定についてりかいしているということになるらしい。が、トレイト境界がまだよくわからん。ちょっとづつ理解していこう

fn longest_with_an_announcement<'a, T>(
    x: &'a str,
    y: &'a str,
    ann: T,
) -> &'a str
where
    T: Display,
{
    println!("Announcement! {}", ann);
    if x.len() > y.len() {
        x
    } else {
        y
    }
}