当我遇到错误时,我正在try 打印一些数据以进行调试.你可以看看full code here号.

当我试图打印从prepare_hash_data()函数返回的数据时出错,该函数返回Vec<u8>.

let data = self.prepare_hash_data()?;      // returns Vec<u8>
println!("{}", String::from_utf8(data)?);  // error here
let mut hasher = Sha256::new();
hasher.input(&data[..]);
println!("{}", hasher.result_str().as_str());
self.hash = hasher.result_str();

下面给出了prepare_hash_data()函数.其他细节将被省略.简单地说,它只是一个返回Vec<u8>的函数

fn prepare_hash_data(&self) -> Result<Vec<u8>, failure::Error> {
        let content = (
            self.hash_prev_block.clone(),
            self.transactions.clone(),
            self.timestamp,
            DIFFICULTY,
            self.nonce
        );
        let bytes = bincode::serialize(&content)?;
        Ok(bytes)
    }

给出的错误是

error[E0382]: borrow of moved value: `data`
  --> src/block.rs:63:23
   |
60 |         let data = self.prepare_hash_data()?;
   |             ---- move occurs because `data` has type `Vec<u8>`, which does not implement the `Copy` trait
61 |         println!("{}", String::from_utf8(data)?);
   |                                          ---- value moved here
62 |         let mut hasher = Sha256::new();
63 |         hasher.input(&data[..]);
   |                       ^^^^ value borrowed here after move

我try 了以下几种方法

  • 实施Copytrait .但是,Vec<u8>不能拥有所描述的hereCopy特征.

  • 查看错误消息中给出的E0382,建议使用两种方法.

    • 使用reference,我们可以让另一个函数borrow 该值,而无需更改其所有权.

      • 但在本例中,我应该如何使用reference呢?
      • 我是否应该将函数签名更改为类似于此的fn prepare_hash_data(&self) -> Result<&Vec<u8>, failure::Error>
    • 值为Rc时,一个值不能由多个变量拥有.

      • 不知道如何实施.
  • 我试着在println!("{}", String::from_utf8(data.clone())?);岁之前克隆数据

    • 但是,它给出了另一个错误backtrace::backtrace::trace_unsynchronized
    • 有关完整的错误日志(log),请单击here

打印一些没有moving就不可能是copiedcloned的数据以供后续行使用,正确的方法应该是什么?

我确实研究了以下解决方案,但无法联系到答案.

推荐答案

我正在try 打印一些数据以进行调试

您提供的代码:

println!("{}", String::from_utf8(data)?);

不是调试打印数据的正确方式.

例如,String::from_utf8 consumes个数据,在此过程中将其销毁.此外,您的数据很可能不是有效的UTF8数据,所以String::from_utf8只会抛出一个错误.

改用调试打印,它可以开箱即用:

println!("{:?}, data);

 


我收回我之前的回答,因为它部分地忽略了你的问题.

它仍然包含有价值的信息,所以我把它保存在下面.如果有人不同意,可以随同这句话一起删除.

 

--Previous Answer--

您的问题是,String::from_utf8 consumes是它的参数,这意味着data以后不能再被访问.

以下是一个更紧凑的示例中的问题:

fn main() {
    let data: Vec<u8> = "Hello!".as_bytes().to_vec();

    // Consumes `data`
    println!("{}", String::from_utf8(data).unwrap());

    // `data` cannot be accessed any more, as it got moved
    // into `String::from_utf8`
    println!("Length of vector: {}", data.len());
}
error[E0382]: borrow of moved value: `data`
 --> src/main.rs:9:38
  |
2 |     let data: Vec<u8> = "Hello!".as_bytes().to_vec();
  |         ---- move occurs because `data` has type `Vec<u8>`, which does not implement the `Copy` trait
...
5 |     println!("{}", String::from_utf8(data).unwrap());
  |                                      ---- value moved here
...
9 |     println!("Length of vector: {}", data.len());
  |                                      ^^^^^^^^^^ value borrowed here after move
  |
help: consider cloning the value if the performance cost is acceptable
  |
5 |     println!("{}", String::from_utf8(data.clone()).unwrap());
  |                                          ++++++++

不过,在您的情况下,这个问题很容易解决.它使用数据的原因是因为String是一个owning变量.它拥有自己的数据,这意味着如果你从Vec创建它,它会在内部存储Vec数据.

还有另一种类型:&str,即字符串片.它与String非常相似,只是它不拥有自己的数据,而只是引用它.这意味着您可以在不 destruct data的情况下创建它:

fn main() {
    let data: Vec<u8> = "Hello!".as_bytes().to_vec();

    // Borrows `data`
    println!("{}", std::str::from_utf8(&data).unwrap());

    // `data` is still accessible because it was only borrowed
    println!("Length of vector: {}", data.len());
}
Hello!
Length of vector: 6

也就是说,给定的解决方案只是一种变通办法.解决这个问题的proper方法是实现Display.

由于您的data对象显然不只是一串字节,因此创建一个表示其含义的适当 struct .

我会考虑两种方式:

  • 一个新类型的 struct ,比如struct MyData(Vec<u8>),你可以为它实现Display.
  • String分.无论如何,当您将其转换为字符串时,为什么不立即将其转换为字符串,作为返回值prepare_hash_data呢?请注意,您将其设置为Vec的原因是它是binary数据,那么您不应该通过from_utf8将其转换为字符串,因为它不是UTF-8数据.然而,如果它是有效的UTF-8数据,请立即使用String,而不是Vec<u8>.而String已经实现了Display,并且无需进一步转换即可打印.

Rust相关问答推荐

如何使用字符串迭代器执行查找?

在Rust中赋值变量有运行时开销吗?

在特征中使用Async时,如何解决不透明类型`impl Future<;out=self>;`不满足其关联的类型边界和警告?

如何使用syn插入 comments ?

支持TLS的模拟HTTP服务器

同时从不同线程调用DLL的不同函数会出现分段错误或产生STATUS_STACK_BUFFER_OVERRUN

如何使用reqwest进行异步请求?

由于生存期原因,返回引用的闭包未编译

Rust 重写函数参数

`UnsafeCell` 在没有锁定的情况下跨线程共享 - 这可能会导致 UB,对吗?

为什么我们有两种方法来包含 serde_derive?

枚举的利基优化如何在 Rust 中工作?

特征中定义的类型与一般定义的类型之间的区别

在单独的线程上运行 actix web 服务器

Rust 中的通用 From 实现

如何断言代码不会在测试中编译?

Rust 中的运行时插件

基于名称是否存在的条件编译

如何在 Rust 中构建一个 str

令人困惑的错误消息? (解包运算符)