rは"0x148de18c.."という16進数の文字列ですが、これは0, x, 1, 4といった文字をUTF-8形式で表現したものです。str::as_bytes()はそのUTF-8表現のバイト列を返すメソッドですので、0, x, 1, 4なら、個々の 文字コード に対応する&[0x30, 0x78, 0x31, 0x34, ..]が返されます。
このことを説明するために、str::as_bytes()で得られた&[u8]の各要素を16進数で表示するコードを書いてみました。
rust
1fn hexdump(bytes: &[u8]) {
2 println!("{} bytes:", bytes.len());
3 for (i, b) in bytes.iter().enumerate() {
4 // b: &u8 の値を2桁の16進数で表示する
5 print!("{:02.x} ", b);
6
7 // 値を16個表示するごとに改行する
8 if (i + 1) % 16 == 0 {
9 println!();
10 }
11 }
12 println!();
13}
14
15let r = "0x148de18c21abe5c1ea727e3204ccbb4cad5f4a9da758cd957f5a6d19454d47b1cb25790cfedc643d1ab730bff97c1d4283da3faacd96b7df0bfb7bdcf3d4d029".to_string();
16let bytes = r.as_bytes();
17hexdump(bytes);
実行すると以下のように表示されます。
plain
1130 bytes:
230 78 31 34 38 64 65 31 38 63 32 31 61 62 65 35
363 31 65 61 37 32 37 65 33 32 30 34 63 63 62 62
434 63 61 64 35 66 34 61 39 64 61 37 35 38 63 64
539 35 37 66 35 61 36 64 31 39 34 35 34 64 34 37
662 31 63 62 32 35 37 39 30 63 66 65 64 63 36 34
733 64 31 61 62 37 33 30 62 66 66 39 37 63 31 64
834 32 38 33 64 61 33 66 61 61 63 64 39 36 62 37
964 66 30 62 66 62 37 62 64 63 66 33 64 34 64 30
1032 39
一方、H512::from_slice()が期待しているのは、文字コードの並びではなく、&[0x14, 0x8d, 0xe1, 0x8c, ..]といった数値データの並びになります。つまりstr::as_bytes()ではなく、16進数の文字列を数値データの並びへと変換する関数が必要です。
そのような関数は標準ライブラリのメソッドを使って簡単に自作できると思いますが、すでにhexというクレートがあるのでそれを使う方法を紹介します。
先ほどのコードをhexクレートで書き換えると以下のようになります。
rust
1// Cargo.tomlに以下を追加
2// [dependencies]
3// hex = "0.3"
4
5use hex;
6
7let r = "0x148de18c21abe5c1ea727e3204ccbb4cad5f4a9da758cd957f5a6d19454d47b1cb25790cfedc643d1ab730bff97c1d4283da3faacd96b7df0bfb7bdcf3d4d029".to_string();
8// 先頭に"0x"があるとhexクレートでデコードできないので削除する
9let r = r.replacen("0x", "", 1);
10// 16進数文字列をhexクレートでデコードする
11let bytes = hex::decode(&r).unwrap(); // Vec<u8>型
12hexdump(&bytes);
plain
164 bytes:
214 8d e1 8c 21 ab e5 c1 ea 72 7e 32 04 cc bb 4c
3ad 5f 4a 9d a7 58 cd 95 7f 5a 6d 19 45 4d 47 b1
4cb 25 79 0c fe dc 64 3d 1a b7 30 bf f9 7c 1d 42
583 da 3f aa cd 96 b7 df 0b fb 7b dc f3 d4 d0 29
期待通りの値になったようです。
このように16進数文字列をhex::decode()でデコードしてから、H512::from_slice()に渡してみてください。
追記 2019-08-07
最後に恐縮ですが、この辺りの理解を深める為のリソースでオススメ等ございましたら後学の為に共有頂けると助かります。
質問者さまがどの程度の知識をお持ちなのかわからないので、理解を深めるために必要になりそうな項目を全て列挙します。すでにご存知のものについては無視してください。
整数と文字列の内部表現(メモリ上でのデータ形式)の違いについて確認する
整数の内部表現
- 2進法と16進法(1バイトの情報はちょうど16進数2桁で表せる)
- 8ビット整数、32ビット整数、64ビット整数など、加減乗除などの演算をCPUがサポートしている形式
- Rustなら
u8, i32, usize型などのスカラ型
- 多バイト長整数(または多倍長整数) ・・・512ビット(64バイト)整数など、演算をCPUがサポートしていない形式
- バイト列で表現することが多い。(Rustなら
Vec<u8>など)
- Rustではたとえばnum-bigintクレートが可変長の多バイト長整数を提供する。primitive-typesクレートはEthereumなどで使われている固定長の多バイト長整数を提供する。(可変長:整数の大きさによってバイト数が変わる、固定長:バイト数が固定されている)
- バイトの並び順 ・・・リトルエンディアンとビッグエンディアン
文字列の内部表現(文字コードとエンコーディング)
- Rustの文字列型(
strとString)はUTF-8エンコーディングを使用している
- 整数と文字列では内部表現が異なる
- たとえば32ビット符号付き整数(Rustでは
i32型)の-42と、文字列(Rustでは&strまたはString型)の"-42"ではメモリ上に異なる情報が格納される
- Rustで文字列
"-42"をi32型の-42に変換するには、str型のparseメソッドを使う(例:"-42".parse::<i32>())
- その逆の変換をするには
ToStringトレイトのto_stringメソッドや、format!マクロを使う
内部表現から外部表現への変換と、その逆の変換について確認する
- 外部表現はデータをファイルに保存したり、他のプログラムとデータをやりとりするときに必要となる
- 外部表現にはバイナリデータ(
println!の"{}"などで表示できない生のバイト列)とテキストデータ(表示可能な文字で構成された文字列)がある
たとえばJSON形式
- JSONは32ビット整数や文字列などは表現できるが、多バイト長整数のようなデータは直接表現できない
- JSONはバイナリデータを扱えない
- 多バイト長整数のようなデータはテキストデータに変換(エンコード)する必要がある
エンコード形式には、16進数文字列や、Base64などがよく使われる
- 前者よりも後者の方が変換後のデータサイズが小さい
- 一般的にハッシュデータは前者、それ以外は後者が好んで使われるが、特に決まりがあるわけではない
これらの概念についてはRustに特化した包括的な説明はなさそうなので、「コンピュータにおける情報の表現」をC言語などを使って解説しているサイトを見るのがいいのかなと思います。たとえば基本的な部分はhttps://www.seiai.ed.jp/sys/text/cs/index.htmlのようなサイトを参照して、そこにない情報(多バイト長整数、16進数文字列、Base64エンコーディングなど)については、それぞれ検索して、出てきた記事を読んでみるといったイメージです。
もしこれらの概念についてはすでに理解されていて、Rustではどう扱えばいいのかだけを知りたいのなら、(宣伝になってしまいますが)たとえば私が共著で執筆した書籍で文字列などについては少し詳しく解説していますので参考になるかもしれません。今年の5月に発売されたばかりの書籍ですので、大きな書店なら置いてあると思います。
実践Rust入門(技術評論社) ISBN978-4-297-10559-4
- 4-2-3 固定精度の整数 ・・・内部表現の説明はないのですが、桁あふれの扱いなどを説明しています
- 4-2-5 文字 ・・・Unicodeスカラ値について説明しています
- 4-3-4 文字列スライス(
str型) ・・・UTF-8エンコーディングなどもごく簡単にですが説明しています
- 5-2-4
String ・・・to_string()とparse()、Stringとstrの比較(図で説明)、など
- 7-9 ライフタイムの詳細:簡単なベクタの実装 ・・・
Stringの内部表現にも使われているVec<T>を真似た型を実装することで、Rustにおける所有権の概念に加えて、データの内部表現についても学べます
書籍の概要については共著者のκeenさんが書かれたブログ記事が参考になると思います。
実践Rust入門を書いたよ
2019/08/05 14:40
2019/08/05 22:57 編集
2019/08/06 01:07
2019/08/07 00:04
2019/08/07 00:19