kdnakt blog

hello there.

Rust dojo第64回を開催した

第64回です。前回はこちら。

kdnakt.hatenablog.com

[第64回の様子]

2023/01/18に第64回を開催した。

内容としてはRust By Example 日本語版19. 標準ライブラリの型の「19.3. 文字列」の後半を最後まで取り組んだ。
参加者は自分を入れて3人。今日は勉強会終了後のSlackでの発言も多めだったので良き。

[学んだこと]

  • 19.3. 文字列
  • Literals and escapesのパートからスタート。
  • Rustで文字列を定義する時に、特殊文字エスケープする方法がいくつかある
  • 基本的にはバックスラッシュ(\)でエスケープできる
    • バックスラッシュ自体が必要なときは連続させることになる:\\
    • この辺は他のプログラミング言語と変わらない
  • "で囲まれた文字列でも'で囲まれた文字でもエスケープは同様
let byte_escape = "I'm writing \x52\x75\x73\x74!";
println!("What are you doing\x3F (\\x3F means ?) {}", byte_escape);

// What are you doing? (\x3F means ?) I'm writing Rust!
  • ユニコードのコードポイントを利用して\u{コードポイント}のようにも書ける
let unicode_codepoint = "\u{211D}";
let character_name = "\"DOUBLE-STRUCK CAPITAL R\"";
println!("Unicode character {} (U+211D) is called {}",
        unicode_codepoint, character_name );

// Unicode character ℝ (U+211D) is called "DOUBLE-STRUCK CAPITAL R"
  • 複数行文字列の場合、通常インデントと改行がそのまま出力されるが、エスケープすることでどちらも無視した出力となる
let long_string = "String literals
                can span multiple lines.
                The linebreak and indentation here ->\
                <- can be escaped too!";
println!("{}", long_string);

// String literals
//                        can span multiple lines.
//                        The linebreak and indentation here -><- can be escaped too!
  • エスケープ対象が多い場合に、エスケープを省略するにはr"文字列"のように書く
let raw_str = r"Escapes don't work here: \x3F \u{211D}";
println!("{}", raw_str);

// エスケープされず以下のように出力される
// Escapes don't work here: \x3F \u{211D}
  • 生文字列中でダブルクオートを利用する場合、以下のように前後にシャープを置く
let quotes = r#"And then I said: "There is no escape!""#;
println!("{}", quotes);

// And then I said: "There is no escape!"
  • 生文字列中で#が必要な場合は、連続する#より1個多い#を前後に置く
let longer_delimiter = r###"A string with "# in it. And even "##!"###;
println!("{}", longer_delimiter);

// A string with "# in it. And even "##!
  • テキストでは前後につけるデリミタの#は65536個までと書かれているが、実際に試してみると255個まででコンパイルエラーがでた
error: too many `#` symbols: raw strings may be delimited by up to 255 `#` symbols, but found 259
  --> src/main.rs:12:28
   |
12 | ... = r###################################################################################################################################################################################################################################################################"A string with "# in it. And even##"#################################################################################################################################################################################################################################################################...
   |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  • バイト文字列を使うと、&strではなくUTF-8の配列として扱える
let bytestring: &[u8; 21] = b"this is a byte string";
println!("A byte string: {:?}", bytestring);

// A byte string: [116, 104, 105, 115, 32, 105, 115, 32, 97, 32, 98, 121, 116, 101, 32, 115, 116, 114, 105, 110, 103]
  • バイト文字列中にエスケープも利用できるが、ユニコードのコードポイントは利用できない
let escaped = b"\x52\x75\x73\x74 as bytes";
println!("Some escaped bytes: {:?}", escaped);

// Some escaped bytes: [82, 117, 115, 116, 32, 97, 115, 32, 98, 121, 116, 101, 115]


let escaped = b"\u{211D} is not allowed";
println!("Some escaped bytes: {:?}", escaped);

// 以下のコンパイルエラー
error: unicode escape in byte string
  --> src/main.rs:13:21
   |
13 |     let escaped = b"\u{211D} is not allowed";
   |                     ^^^^^^^^ unicode escape in byte string
   |
   = help: unicode escape sequences cannot be used as a byte or in a byte string
  • 生文字列同様、生バイト文字列も利用できる
let raw_bytestring = br"\u{211D} is not escaped here";
println!("{:?}", raw_bytestring);

// [92, 117, 123, 50, 49, 49, 68, 125, 32, 105, 115, 32, 110, 111, 116, 32, 101, 115, 99, 97, 112, 101, 100, 32, 104, 101, 114, 101]

// 改行も利用可能
let _quotes = br#"You can also use "fancier" formatting, \
            like with normal raw strings"#;
  • バイト文字列をstrに変換するには以下のようにする
use std::str;

let raw_bytestring = br"\u{211D} is not escaped here";
if let Ok(my_str) = str::from_utf8(raw_bytestring) {
    println!("And the same as text: '{}'", my_str);
}

// And the same as text: '\u{211D} is not escaped here'
  • バイト文字列はUTF-8でなくてもよい:SJISなども利用可能
    • ただし、
use std::str;
// SHIFT-JISで「ようこそ」
let shift_jis = b"\x82\xe6\x82\xa8\x82\xb1\x82\xbb"; 

// UTF-8には変換できない
match str::from_utf8(shift_jis) {
    Ok(my_str) => println!("Conversion successful: '{}'", my_str),
    Err(e) => println!("Conversion failed: {:?}", e),
};
// Conversion failed: Utf8Error { valid_up_to: 0, error_len: Some(1) }

[まとめ]

モブプログラミングスタイルでRust dojoを開催した。
短い章だと思ったけどなかなか骨のある章だった...文字列、奥が深い。

今週のプルリクエストはこちら。 

github.com