Closed3

Rust - str が引数/戻り値で使えない理由

philomagiphilomagi

https://stackoverflow.com/questions/49393462/what-does-str-does-not-have-a-constant-size-known-at-compile-time-mean-and

What it means is harder to explain succinctly. Rust has a number of types that are unsized. The most prevalent ones are str and [T]. Contrast these types to how you normally see them used: &str or &[T]. You might even see them as Box<str> or Arc<[T]>. The commonality is that they are always used behind a reference of some kind.

Because these types don't have a size, they cannot be stored in a variable on the stack — the compiler wouldn't know how much stack space to reserve for them! That's the essence of the error message.

philomagiphilomagi

https://ja.stackoverflow.com/questions/65708/rustのresultについての質問-errore0277-the-size-for-values-of-type-str-cannot-be-kno

まずはエラーメッセージそのもの、「the size for values of type str cannot be known at compilation time」について

str を &'static str にすれば解決します。 Rustでは勝手にポインタが作られたりしないので str は任意長の文字列そのものを表わします。これを関数から返すということは、例えば1000文字の文字列ならば1000文字分のデータをコピーして呼出元に返すことになります。今のところRustは任意長のデータをスタックにコピーする操作は許していません。そこで &str とポインタを介すると16バイト(ポインタサイズ8バイト+strのサイズ8バイト)と定サイズになるのでエラーにならなくなります。
「str 型を生で使うことはない」と覚えてしまっていいでしょう。

philomagiphilomagi

str は任意長の文字列そのものを表わします[1]

今のところRustは任意長のデータをスタックにコピーする操作は許していません[2]

この2点を前提とすれば、以下のように説明できるだろうか。

str は任意帳の文字列そのものを表す、すなわち

[0] -> 'H'
[1] -> 'e'
[2] -> 'l'
[3] -> 'l'
[4] -> 'o'

の構造で表される「文字のリスト」としての文字列そのものである。

関数の引数として渡された値は、スタックへ乗せられる[3]。しかし、スタックへ載せられるデータは全て既知の固定サイズである → 任意長のデータはスタックへは乗せられない(ヒープに乗せなくてはならない)ので、 str を引数として使うことはできない。よって、コンパイルエラーとなる。
また、関数の戻り値もやはりスタックへ乗せられる[4]ので、戻り値もやはり既知の固定サイズでなくてはならず、任意長のデータである str は利用できない。

代わりに &str として str への参照を、すなわちポインタを使えばそれは固定値となる[5]ので、コンパイルエラーにならない。

脚注
  1. https://doc.rust-jp.rs/book-ja/ch08-02-strings.html#文字列でutf-8でエンコードされたテキストを保持する "Rustには、言語の核として1種類しか文字列型が存在しません。 文字列スライスのstrで、通常借用された形態&strで見かけます。" ↩︎

  2. https://doc.rust-jp.rs/book-ja/ch04-01-what-is-ownership.html "スタックを高速にする特性は他にもあり、それはスタック上のデータは全て既知の固定サイズでなければならないということです。" ↩︎

  3. https://doc.rust-jp.rs/book-ja/ch04-01-what-is-ownership.html
    "コードが関数を呼び出すと、関数に渡された値(ヒープのデータへのポインタも含まれる可能性あり)と、 関数のローカル変数がスタックに載ります。関数の実行が終了すると、それらの値はスタックから取り除かれます。" ↩︎

  4. https://brain.cc.kogakuin.ac.jp/~kanamaru/lecture/MP/final/part06/node9.html "square 関数が終了するとスタック領域は図 7(c) のようになり、 戻り値 $v0 の値が変数 b に代入されてプログラムが終了する。" ↩︎

  5. https://ja.stackoverflow.com/questions/65708/rustのresultについての質問-errore0277-the-size-for-values-of-type-str-cannot-be-kno "そこで &str とポインタを介すると16バイト(ポインタサイズ8バイト+strのサイズ8バイト)と定サイズになるのでエラーにならなくなります。" ↩︎

このスクラップは2021/11/03にクローズされました