移动发生是因为`data`具有类型`Vec<u8>`,它没有实现`Copy` trait。

huangapple go评论50阅读模式
英文:

move occurs because `data` has type `Vec<u8>`, which does not implement the `Copy` trait

问题

错误发生在我尝试打印从 prepare_hash_data() 函数返回的数据时,该函数返回一个 Vec<u8>

let data = self.prepare_hash_data()?;      // 返回 Vec<u8>
println!("{}", String::from_utf8(data)?);  // 错误发生在这里
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

我尝试了以下方法

  • 实现 Copy trait。但是,Vec<u8> 不能实现 Copy trait,如这里所述

  • 查看错误信息中给出的E0382 ,有两种建议的方法。

    • 使用 引用,我们可以让另一个函数借用该值而不改变其所有权。

      • 但是我应该如何在这个例子中使用 引用
      • 我是否应该将函数签名更改为类似这样的形式 fn prepare_hash_data(&self) -> Result<&Vec<u8>, failure::Error>
    • 使用 Rc,一个值不能被多个变量拥有。

      • 不知道如何实现。
  • 我尝试通过 println!("{}", String::from_utf8(data.clone())?); 克隆数据。

    • 但是,它引发另一个错误 backtrace::backtrace::trace_unsynchronized
    • 完整的错误日志,请点击此处

在不在后续行中 移动 它的情况下打印无法 复制克隆 的数据的正确方法是什么?

我查看了以下解决方案,但无法与答案相关联。

英文:

I am trying to print some data for debugging purposes when I encountered an error. You can have a look at the full code here.

The error occurred when I tried to print data returned from the prepare_hash_data() function, which returns a Vec&lt;u8&gt;.

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

The prepare_hash_data() function is given below. Other details are omitted. Simply, it is just a function that returns Vec&lt;u8&gt;

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

The error given is

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

I tried the following ways

  • Implementing Copy trait. But, Vec&lt;u8&gt; can't have the Copy trait as described here.

  • Looking at E0382 given in the error message, there are two ways suggested.

    • Using a reference, we can let another function borrow the value without changing its ownership.

      • But how should I use reference in this example?
      • Should I change the function signature to something like this fn prepare_hash_data(&amp;self) -&gt; Result&lt;&amp;Vec&lt;u8&gt;, failure::Error&gt;?
    • With Rc, a value cannot be owned by more than one variable.

      • Don't know how to implement.
  • I tried cloning the data by println!(&quot;{}&quot;, String::from_utf8(data.clone())?);

    • But, it gives another error backtrace::backtrace::trace_unsynchronized
    • For the full error log, click here

What should be the correct approach to printing some data that can't be copied or cloned without moving it for later usage in subsequent lines?

I did look at the following solutions but can't relate the answer.

答案1

得分: 3

>我试图打印一些数据以进行调试目的

您提供的代码:

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

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

首先,String::from_utf8 消耗 了数据,在此过程中销毁了它。而且,您的数据很可能不是有效的UTF8数据,所以String::from_utf8 只会抛出一个错误。

相反,请使用调试打印,它可以直接使用:

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

&nbsp;


我撤回了之前的答案,因为它部分地忽略了您的问题。

它仍然包含有价值的信息,所以我将它保留在下面。如果有人不同意,请随时删除它,以及这句话。

&nbsp;

--之前的答案--

您的问题是String::from_utf8 消耗 了它的参数,也就是说,之后无法再访问data

以下是一个更简洁的示例来说明您的问题:

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

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

    // 无法再访问 `data`,因为它被移动到了 `String::from_utf8`
    println!("向量的长度:{}", data.len());
}
error[E0382]: borrow of moved value: `data`
 --&gt; 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!("向量的长度:{}", 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是一个拥有数据的变量。它拥有它的数据,这意味着,如果您从Vec创建它,它会在内部存储Vec的数据。

还有另一种类型:&str,一个字符串切片。它与String非常相似,只是它不拥有它的数据,而只是引用它。这意味着您可以创建它而不销毁data

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

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

    // `data` 仍然可以访问,因为它只是被借用了
    println!("向量的长度:{}", data.len());
}
Hello!
向量的长度:6

也就是说,所提供的解决方案只是一种权宜之计。正确的方法是实现Display

由于您的data对象显然不仅仅是一堆字节,而是有更多意义的,创建一个适当表示其含义的结构体。

我会考虑两种方法:

  • 一个新类型结构体,比如struct MyData(Vec<u8>),您可以为其实现Display
  • 一个String。由于您无论如何都将其转换为字符串,为什么不直接将其作为prepare_hash_data的返回值呢?请注意,如果您将其作为Vec的原因是它是二进制数据,那么您不应该通过from_utf8将其转换为字符串,因为它不是UTF-8数据。但如果它是有效的UTF-8数据,直接使用String,而不是Vec<u8>String已经实现了Display,可以直接打印,无需进一步转换。
英文:

>I am trying to print some data for debugging purposes

The code you provided:

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

Is not the correct way to debug-print data.

For one, String::from_utf8 consumes the data, destroying it in the process. Further, your data most likely isn't valid UTF8 data, so String::from_utf8 will only throw an error.

Use debug printing instead, it works out of the box:

println!(&quot;{:?}, data);

&nbsp;


I retract my previous answer because it partially missed your problem.

It still contained valuable information, so I have kept it below. If someone disagrees, feel free to delete it together with this sentence.

&nbsp;

--Previous Answer--

Your problem is that String::from_utf8 consumes its argument, meaning, data cannot be accessed any more afterwards.

Here is your problem in a more compact example:

fn main() {
    let data: Vec&lt;u8&gt; = &quot;Hello!&quot;.as_bytes().to_vec();

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

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

In your case this can be easily fixed, though. The reason it consumes the data is because String is an owning variable. It owns its data, meaning, if you create it from a Vec, it stores the Vec data internally.

There is another type: &amp;str, a string slice. It's very similar to String, just that it doesn't own its data, but merely references it. That means you can create it without destroying data:

fn main() {
    let data: Vec&lt;u8&gt; = &quot;Hello!&quot;.as_bytes().to_vec();

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

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

That said, the given solution is only a workaround. The proper way to fix this is to implement Display.

As your data object clearly has more meaning than just a bunch of bytes, create a proper struct that represents its meaning.

There are two ways I would consider:

  • A newtype struct, like struct MyData(Vec&lt;u8&gt;), for which you can implement Display.
  • A String. As you convert it to a string anyway, why not just make it a string right away, as the return value of prepare_hash_data? Note that if your reason to have it a Vec is that it is binary data, then you shouldn't convert it to a string via from_utf8, as it's not UTF-8 data. If it is valid UTF-8 data, however, use a String right away, not a Vec&lt;u8&gt;. And String already implements Display and can be printed without further conversion.

huangapple
  • 本文由 发表于 2023年2月19日 20:59:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/75500317.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定