以下の様にr
の文字列型を受け取った後:
let mut r = String::new(); // some functions and returns new_data : &[u8] r = String::from_utf8(Vec::from(new_data)).unrwap(); println!("result is {}", r); // "0x148de18c21abe5c1ea727e3204ccbb4cad5f4a9da758cd957f5a6d19454d47b1cb25790cfedc643d1ab730bff97c1d4283da3faacd96b7df0bfb7bdcf3d4d029"
再度このr
の値をprimitive_types
クレートを使い、64bytes
型に変換して受け渡しをしたいのですが、なぜか以下の様にするとエラーになってしまいます。
crate primitive_types::H512; // 中略 let b = H512::from_slice(&r.as_bytes);
thread 'main' panicked at 'assertion failed: `(left == right)` left: `132`, right: `64`', /Users/hogehoge/.cargo/registry/src/github.com-1ecc6299db9ec823/primitive-types-0.3.0/src/lib.rs:68:1 note: Run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
どなたか方法をご教授頂けますとさいわいです。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

回答3件
0
ベストアンサー
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
型などのスカラ型
- Rustなら
- 多バイト長整数(または多倍長整数) ・・・512ビット(64バイト)整数など、演算をCPUがサポートしていない形式
- バイト列で表現することが多い。(Rustなら
Vec<u8>
など) - Rustではたとえばnum-bigintクレートが可変長の多バイト長整数を提供する。primitive-typesクレートはEthereumなどで使われている固定長の多バイト長整数を提供する。(可変長:整数の大きさによってバイト数が変わる、固定長:バイト数が固定されている)
- バイト列で表現することが多い。(Rustなら
- バイトの並び順 ・・・リトルエンディアンとビッグエンディアン
文字列の内部表現(文字コードとエンコーディング)
- 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!
マクロを使う
- たとえば32ビット符号付き整数(Rustでは
内部表現から外部表現への変換と、その逆の変換について確認する
- 外部表現はデータをファイルに保存したり、他のプログラムとデータをやりとりするときに必要となる
- 外部表現にはバイナリデータ(
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さんが書かれたブログ記事が参考になると思います。
投稿2019/08/05 10:50
編集2019/08/07 00:00総合スコア2055
0
If the length of src and the number of bytes in Self do not match.
該当部分のpanicsを見ると、パラメータのデータ長が合わない場合に発生するようですね。
https://docs.rs/primitive-types/0.3.0/primitive_types/struct.H512.html#method.from_slice
投稿2019/08/05 10:14
総合スコア88
0
使ったことのないクレートなので間違えていたら申し訳ないですが、ドキュメントを読む限りprimitive_types::H512::from_slice
は64バイトの&[u8]
スライスが渡されることを想定しているのだと思います。
その一方で、new_data
はそのスライスそのものでなく、何らかの64バイトのバイナリ列の16進数表示(を引用符で囲んだもの)の文字列のように見えます。もしその元となったスライスなどがあるのでしたら、それをそのままH512::from_slice
に渡してみてはいかがでしょうか。
投稿2019/08/02 09:20
総合スコア33
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
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