英文:
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
。 - 完整的错误日志,请点击此处
- 但是,它引发另一个错误
在不在后续行中 移动
它的情况下打印无法 复制
或 克隆
的数据的正确方法是什么?
我查看了以下解决方案,但无法与答案相关联。
- move occurs because value has type Vec
, which does not implement the Copy
trait - 'move occurs because value has type' Rust error
英文:
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<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();
The prepare_hash_data()
function is given below. Other details are omitted. Simply, it is just a function that returns 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)
}
The error given is
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
I tried the following ways
-
Implementing
Copy
trait. But,Vec<u8>
can't have theCopy
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(&self) -> Result<&Vec<u8>, failure::Error>
?
- But how should I use
-
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!("{}", String::from_utf8(data.clone())?);
- But, it gives another error
backtrace::backtrace::trace_unsynchronized
- For the full error log, click here
- But, it gives another error
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);
我撤回了之前的答案,因为它部分地忽略了您的问题。
它仍然包含有价值的信息,所以我将它保留在下面。如果有人不同意,请随时删除它,以及这句话。
--之前的答案--
您的问题是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`
--> 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!("{}", 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!("{:?}, data);
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.
--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<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());
| ++++++++
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: &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<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
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<u8>)
, for which you can implementDisplay
. - A
String
. As you convert it to a string anyway, why not just make it a string right away, as the return value ofprepare_hash_data
? Note that if your reason to have it aVec
is that it is binary data, then you shouldn't convert it to a string viafrom_utf8
, as it's not UTF-8 data. If it is valid UTF-8 data, however, use aString
right away, not aVec<u8>
. AndString
already implementsDisplay
and can be printed without further conversion.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论