我想在 Rust 中将字符串(SHA256 哈希)转换为十六进制:
extern crate crypto;
extern crate rustc_serialize;
use rustc_serialize::hex::ToHex;
use crypto::digest::Digest;
use crypto::sha2::Sha256;
fn gen_sha256(hashme: &str) -> String {
let mut sh = Sha256::new();
sh.input_str(hashme);
sh.result_str()
}
fn main() {
let hash = gen_sha256("example");
hash.to_hex()
}
编译器说:
error[E0599]: no method named `to_hex` found for type `std::string::String` in the current scope
--> src/main.rs:18:10
|
18 | hash.to_hex()
| ^^^^^^
我可以看出这是真的;看起来 仅针对
[u8]
实施。
我该怎么办? Rust 中是否没有实现从字符串转换为十六进制的方法?
我的 Cargo.toml 依赖项:
[dependencies]
rust-crypto = "0.2.36"
rustc-serialize = "0.3.24"
edit我刚刚意识到该字符串是already,来自rust-crypto库的十六进制格式。哦。
我会在这里冒险,并建议解决方案是
hash
为 Vec<u8>
类型。
问题是,虽然您确实可以使用
String
将 &[u8]
转换为 as_bytes
,然后使用 to_hex
,但您首先需要有一个有效的 String
对象来开始。
虽然任何
String
对象都可以转换为 &[u8]
,但反之则不然。 String
对象仅用于保存有效的 UTF-8 编码的 Unicode 字符串:并非所有字节模式都符合条件。
因此,
gen_sha256
产生String
是不正确的。更正确的类型是 Vec<u8>
,它确实可以接受任何字节模式。从那时起,调用 to_hex
就足够简单了:
hash.as_slice().to_hex()
看来
ToHex
的来源有我正在寻找的解决方案。它包含一个测试:
#[test]
pub fn test_to_hex() {
assert_eq!("foobar".as_bytes().to_hex(), "666f6f626172");
}
我修改后的代码是:
let hash = gen_sha256("example");
hash.as_bytes().to_hex()
这似乎有效。如果有人有替代答案,我将需要一些时间才能接受此解决方案。
可以使用如下函数生成十六进制表示:
pub fn hex_push(buf: &mut String, blob: &[u8]) {
for ch in blob {
fn hex_from_digit(num: u8) -> char {
if num < 10 {
(b'0' + num) as char
} else {
(b'A' + num - 10) as char
}
}
buf.push(hex_from_digit(ch / 16));
buf.push(hex_from_digit(ch % 16));
}
}
这比当前语言中实现的通用基数格式更有效。
这是一个基准:
test bench_specialized_hex_push ... bench: 12 ns/iter (+/- 0) = 250 MB/s
test bench_specialized_fomat ... bench: 42 ns/iter (+/- 12) = 71 MB/s
test bench_specialized_format ... bench: 47 ns/iter (+/- 2) = 63 MB/s
test bench_specialized_hex_string ... bench: 76 ns/iter (+/- 9) = 39 MB/s
test bench_to_hex ... bench: 82 ns/iter (+/- 12) = 36 MB/s
test bench_format ... bench: 97 ns/iter (+/- 8) = 30 MB/s
感谢 freenode
##rustirc 频道中的用户
jey
。您可以只使用 fmt
提供的十六进制表示,
>> let mut s = String::new();
>> use std::fmt::Write as FmtWrite; // renaming import to avoid collision
>> for b in "hello world".as_bytes() { write!(s, "{:02x}", b); }
()
>> s
"68656c6c6f20776f726c64"
>>
或者有点傻,
>> "hello world".as_bytes().iter().map(|x| format!("{:02x}", x)).collect::<String>()
"68656c6c6f20776f726c64"
使用
hex
板条箱,非常简单:
use hex;
println!("{}", hex::encode(String("some str")));