From https://doc.rust-lang.org/rust-by-example/trait/dyn.html, as known, the dyn trait's size is not known when compiling, so we can not use it as a return value. But when can create a reference and put it in box, the box has fixed size.
But I met a problem, how can I box a tait which has an interface to consume it.
#[tokio::test]
async fn test_dyn_trait() {
trait Consume {
fn usage(self) -> String;
}
trait Refer {
fn usage(&self) -> String;
}
struct Man {
name: String,
}
impl Consume for Man {
fn usage(self) -> String {
let Man { name } = self;
return name;
}
}
impl Refer for Man {
fn usage(&self) -> String {
return self.name.clone();
}
}
let a: Box<dyn Consume> = Box::new(Man {
name: "aaron".to_string(),
});
let b: Box<dyn Refer> = Box::new(Man {
name: "aaron".to_string(),
});
println!("a: {}", a.usage()); // cannot move a value of type dyn Consume: the size of dyn Consume cannot be statically determined
println!("b: {}", b.usage()); // it is ok
}
This is impossible. Rust has something called object safety, which prevent creating trait objects of traits that have a method that either takes or returns Self (and couple other things).
Related
The blockchain struct definition, It defines a type and i use the type
pub struct Blockchain<T = SledDb> {
pub storage: T,
pub chain: Vec<Block>,
pub tip: Arc<RwLock<String>>,
pub height: AtomicUsize,
pub mempool: Mempool,
pub wallet: Wallet,
pub accounts: Account,
pub stakes: Stake,
pub validators: Validator,
}
This code is checking if stake is valid.The code for mining a block, the error is immited by is_staking_valid function. I don't know what type its asking for since i already specified one.
impl<T: Storage> Blockchain<T> {
pub fn is_staking_valid(
balance: u64,
difficulty: u32,
timestamp: i64,
prev_hash: &String,
address: &String,
) -> bool {
let base = BigUint::new(vec![2]);
let balance_diff_mul = base.pow(256) * balance as u32;
let balance_diff = balance_diff_mul / difficulty as u64;
let data_str = format!("{}{}{}", prev_hash, address, timestamp.to_string());
let sha256_hash = digest(data_str);
let staking_hash = BigUint::parse_bytes(&sha256_hash.as_bytes(), 16).expect("msg");
staking_hash <= balance_diff
}
pub fn mine_block(&mut self, data: &str) -> Option<Block> {
if self.mempool.transactions.len() < 2 {
info!("Skipping mining because no transaction in mempool");
return None;
}
let balance = self
.stakes
.get_balance(&self.wallet.get_public_key())
.clone();
let difficulty = self.get_difficulty();
info!("New block mining initialized with difficulty {}", difficulty);
let timestamp = Utc::now().timestamp();
let prev_hash = self.chain.last().unwrap().hash.clone();
let address = self.wallet.get_public_key();
if Blockchain::is_staking_valid(balance, difficulty, timestamp, &prev_hash, &address){
let block = self.create_block(&data, timestamp);
self.storage.update_blocks(&prev_hash, &block, self.height.load(Ordering::Relaxed));
Some(block)
} else {
None
}
}
}
Please find the compiler error below
error[E0282]: type annotations needed
--> src/blocks/chain.rs:173:12
|
173 | if Blockchain::is_staking_valid(balance, difficulty, timestamp, &prev_hash, &address){
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `T`
For more information about this error, try `rustc --explain E0282`.
Minimized example:
pub struct Blockchain<T> {
pub storage: T,
}
impl<T> Blockchain<T> {
pub fn is_staking_valid() {
todo!()
}
pub fn mine_block(&mut self) {
Blockchain::is_staking_valid();
}
}
Playground
The reason for this error is that Blockchain::<T1>::is_staking_valid and Blockchain::<T2>::is_staking_valid are, as well as compiler is concerned, two separate, entirely unrelated functions. Yes, they have the same code, and yes, they will be deduplicated by the optimizer, but this doesn't have to be the case - e.g., if this function used some associated item available on T:
trait Stakable {
const IS_VALID: bool;
}
impl Stakable for () {
const IS_VALID: bool = false;
}
impl Stakable for i32 {
const IS_VALID: bool = true;
}
struct Blockchain<T> {
pub _storage: T,
}
impl<T: Stakable> Blockchain<T> {
fn validate() {
if !T::IS_VALID {
panic!("Type is not valid");
}
}
}
fn main() {
// This panics - we catch this panic and show that it has indeed happened
std::panic::catch_unwind(|| Blockchain::<()>::validate()).unwrap_err();
// This executes successfully
Blockchain::<i32>::validate();
}
Playground
Because of the possible ambiguity, compiler refuses to choose by itself and forces you to make the selection explicitly.
So, you have several possible ways to go:
Make is_staking_valid a free function, instead of associated function of Blockchain. In this case, it won't be able to depend on Blockchain's type parameter, therefore the call will be unambiguous.
Call Self::is_staking_valid instead of Blockchain::is_staking_valid. In this case, Self will be replaced with Blockchain::<T>, with T taken from the currently executed method; this will, again, resolve ambiguity.
Make is_staking_valid a method on Blockchain, i.e. make it receive &self, and call it via self.is_staking_valid().
Not recommended, but still possible, - make is_staking_valid an associated function on Blockchain<T> for some specific T, e.g.:
pub struct Blockchain<T> {
pub storage: T,
}
impl Blockchain<()> {
// Note - no free type parameters here!
pub fn is_staking_valid() {
todo!()
}
}
impl<T> Blockchain<T> {
pub fn mine_block(&mut self) {
// Here, `Blockchain` is `Blockchain::<()>` - the method is set
Blockchain::is_staking_valid();
}
}
I'm playing with Rust and here is the code:
pub trait TFilter {
fn get_text(&self) -> &String;
}
...
pub struct ContentFilter {
text: String,
domains: String,
body: String,
}
impl TFilter for ContentFilter {
fn get_text(&self) -> &String {
return &self.text
}
}
impl ContentFilter {
pub fn from_text(text: String, domains: String, body: String) -> Self {
return ContentFilter {
text,
domains,
body
}
}
}
...
fn filter_from_text(&mut self, text: String) -> &Box<dyn TFilter> {
...
&Box::new(ContentFilter::from_text(text, domains, body)) // is returned
...
}
I'm getting the error message:
expected trait object dyn filter::TFilter, found struct filter::ContentFilter
= note: expected reference &std::boxed::Box<(dyn filter::TFilter + 'static)>
found reference &std::boxed::Box<filter::ContentFilter>
This is misleading as:
it does implements the trait
the compiler does know the size of ContentFilter struct
Any clue?
PS. The code is not good anyway (as it's unclear who owns the Box that is returned), but the message is misleading.
PPS. How a caching proxy can be implemented then:
pub trait TFilterBuilder {
fn filter_from_text(&mut self, text: String) -> &Box<dyn TFilter>;
}
...
struct FilterCachingProxy {
filter_builder: Box<dyn TFilterBuilder>,
cache: Box<dyn TFilterCache>
}
impl FilterCachingProxy {
fn new_for_builder(filter_builder: Box<dyn TFilterBuilder>, cache: Box<dyn TFilterCache>) -> Self {
return FilterCachingProxy {
filter_builder,
cache
}
}
}
impl TFilterBuilder for FilterCachingProxy {
fn filter_from_text(&mut self, text: String) -> &Box<dyn TFilter> {
let boxed_filter = match self.cache.get(&text) {
Some(found_boxed_filter) => found_boxed_filter,
_ => {
// delegate creation to wrapped TFilterBuilder impl (`filter_builder`)
let boxed_filter = self.filter_builder.filter_from_text(text.clone());
// ... and put to the cache
self.cache.put(&text, &boxed_filter); // boxed_filter should be moved to make cache own it?
&boxed_filter // looks strange: who owns it then?
}
};
return boxed_filter;
}
}
The return type should be just a Box, not a reference to a Box:
fn filter_from_text(&mut self, text: String) -> Box<dyn TFilter> {
...
Box::new(ContentFilter::from_text(text, domains, body)) // is returned
}
(Minimal compiling version on the playground)
The box is newly created in your function, so you have to return ownership of the box. It's impossible to just return a reference to a temporary, since it will go out of scope at the end of the function.
A side effect of this change is that the unsized coercion from Box<ContentFilter> to Box<dyn TFilter> will now actually work. Coercions are only applied in coercion site like the return value. In your code, the type that needs to be coerced is nested in a reference, so no unsized coercion is performed by the compiler.
I have the following:
pub struct OpBStruct {
title: String,
output_vale: i32,
}
impl OpBStruct {
pub fn new_OpB(in_title: String, in_output_vale: i32) -> OpBStruct {
OpBStruct {
title: in_title,
output_vale: in_output_vale,
}
}
}
pub struct OpCStruct {
title: String,
another_value: String,
output_vale: i32,
}
impl OpCStruct {
pub fn new_OpC(in_title: String, in_another_value: String, in_output_vale: i32) -> OpCStruct {
OpCStruct {
title: in_title,
another_value: in_another_value,
output_vale: in_output_vale,
}
}
}
impl A {
pub fn new_A(in_name: String, in_operator: Op) -> A {
A {
name: in_name,
operator: in_operator,
}
}
}
pub enum Op {
OpB(OpBStruct),
OpC(OpCStruct),
}
pub struct A {
name: String,
operator: Op,
}
impl A {
pub fn new_A(in_name: String, in_operator: Op) -> A {
A {
name: in_name,
operator: in_operator,
}
}
}
The exact structure of OpBStruct and OpCStruct are arbitrary and could be anything.
How do I make sure OpBStruct and OpCStruct implement a certain trait?
trait OpTrait {
pub fn get_op_output(&self) -> i32;
}
I thought about making a sort of constructor function that checked for an OpTrait trait requirement and it would be the only way one could create an Op instance, but each operator requires different initialization parameters and there's no way to specify a variable number of inputs for a function in Rust.
Something like this doesn't work because there's no way to input the initialization parameters:
pub fn new_op<T: OpTrait>(operator: T) {
// --snip--
}
I thought about somehow using the new_A method implemented on A to check if the in_operator has implemented the trait, but I'm not sure how to do that either.
What is the correct pattern for this? If there is none, I can just implement the trait for each Op with no sort of interface around it.
I would also recommend writing a test, however you can write a function which is generic over a type but takes no arguments:
struct X {}
trait Y {
fn yo();
}
fn is_y<T: Y>(){}
Then you can add the following line to do the check
is_y::<X>();
which will compile only if X implements Y.
Using a unit test would be a fairly straightforward way to enforce that you want a given trait on a struct. You can do it via implicit test code, but a small utility function to do so can express the intent a little more clearly.
If you have indicated trait inputs on functions in the rest of the code, it might come out fairly naturally without the unit test. The test has the advantage of letting you have an opportunity to explicitly check some invariant of the trait implementation too.
struct A {
val: u8,
}
struct B {
val: u32,
}
trait ExpandToU64 {
fn to_u64(&self) -> u64;
}
impl ExpandToU64 for A {
fn to_u64(&self) -> u64
{
self.val as u64
}
}
fn trait_tester<E>(a: E)
where E: ExpandToU64
{
// the utility function doesn't have to even use the trait...
// but you probably want to exercise the logic a bit
//let v = a.to_u64();
let v = 24u64;
println!("{:?}", v);
}
#[test]
fn test_needs_trait_ExpandToU64() {
let a = A { val:1 };
trait_tester(a);
let b = B { val:2 };
trait_tester(b);
// This fails with a compile error
// "the trait `ExpandToU64` is not implemented for `B`"
}
I'm trying to do the equivalent of Ruby's Enumerable.collect() in Rust.
I have an Option<Vec<Attachment>> and I want to create a Option<Vec<String>> from it, with String::new() elements in case of None guid.
#[derive(Debug)]
pub struct Attachment {
pub guid: Option<String>,
}
fn main() {
let ov: Option<Vec<Attachment>> =
Some(vec![Attachment { guid: Some("rere34r34r34r34".to_string()) },
Attachment { guid: Some("5345345534rtyr5345".to_string()) }]);
let foo: Option<Vec<String>> = match ov {
Some(x) => {
x.iter()
.map(|&attachment| attachment.guid.unwrap_or(String::new()))
.collect()
}
None => None,
};
}
The error in the compiler is clear:
error[E0277]: the trait bound `std::option::Option<std::vec::Vec<std::string::String>>: std::iter::FromIterator<std::string::String>` is not satisfied
--> src/main.rs:15:18
|
15 | .collect()
| ^^^^^^^ the trait `std::iter::FromIterator<std::string::String>` is not implemented for `std::option::Option<std::vec::Vec<std::string::String>>`
|
= note: a collection of type `std::option::Option<std::vec::Vec<std::string::String>>` cannot be built from an iterator over elements of type `std::string::String`
If I remember what I've read from the documentation so far, I cannot implement traits for struct that I don't own.
How can I do this using iter().map(...).collect() or maybe another way?
You should read and memorize all of the methods on Option (and Result). These are used so pervasively in Rust that knowing what is present will help you immensely.
For example, your match statement is Option::map.
Since you never said you couldn't transfer ownership of the Strings, I'd just do that. This will avoid any extra allocation:
let foo: Option<Vec<_>> =
ov.map(|i| i.into_iter().map(|a| a.guid.unwrap_or_else(String::new)).collect());
Note we don't have to specify the type inside the Vec; it can be inferred.
You can of course introduce functions to make it cleaner:
impl Attachment {
fn into_guid(self) -> String {
self.guid.unwrap_or_else(String::new)
}
}
// ...
let foo: Option<Vec<_>> = ov.map(|i| i.into_iter().map(Attachment::into_guid).collect());
If you don't want to give up ownership of the String, you can do the same concept but with a string slice:
impl Attachment {
fn guid(&self) -> &str {
self.guid.as_ref().map_or("", String::as_str)
}
}
// ...
let foo: Option<Vec<_>> = ov.as_ref().map(|i| i.iter().map(|a| a.guid().to_owned()).collect());
Here, we have to use Option::as_ref to avoid moving the guid out of the Attachment, then convert to a &str with String::as_str, providing a default value. We likewise don't take ownership of the Option of ov, and thus need to iterate over references, and ultimately allocate new Strings with ToOwned.
Here is a solution that works:
#[derive(Debug)]
pub struct Attachment {
pub guid: Option<String>,
}
fn main() {
let ov: Option<Vec<Attachment>> =
Some(vec![Attachment { guid: Some("rere34r34r34r34".to_string()) },
Attachment { guid: Some("5345345534rtyr5345".to_string()) }]);
let foo: Option<Vec<_>> = ov.map(|x|
x.iter().map(|a| a.guid.as_ref().unwrap_or(&String::new()).clone()).collect());
println!("{:?}", foo);
}
One of the issues with the above code is stopping the guid being moved out of the Attachment and into the vector. My example calls clone to move cloned instances into the vector.
This works, but I think it looks nicer wrapped in a trait impl for Option<T>. Perhaps this is a better ... option ...:
trait CloneOr<T, U>
where U: Into<T>,
T: Clone
{
fn clone_or(&self, other: U) -> T;
}
impl<T, U> CloneOr<T, U> for Option<T>
where U: Into<T>,
T: Clone
{
fn clone_or(&self, other: U) -> T {
self.as_ref().unwrap_or(&other.into()).clone()
}
}
#[derive(Debug)]
pub struct Attachment {
pub guid: Option<String>,
}
fn main() {
let ov: Option<Vec<Attachment>> =
Some(vec![Attachment { guid: Some("rere34r34r34r34".to_string()) },
Attachment { guid: Some("5345345534rtyr5345".to_string()) },
Attachment { guid: None }]);
let foo: Option<Vec<_>> =
ov.map(|x| x.iter().map(|a| a.guid.clone_or("")).collect());
println!("{:?}", foo);
}
Essentially the unwrapping and cloning is hidden behind a trait implementation that attaches to Option<T>.
Here it is running on the playground.
I'm trying to implement a simple builder but struggling with lifetimes. The following is giving error: borrowed value does not live long enough. This question seems similar. If I store t in a mutable variable and then call s and finalize it works, but I want to get the one liner to work. What am I doing wrong?
struct Type<'a> {
s: &'a String,
}
struct TypeBuilder {
s: String,
}
impl TypeBuilder {
fn new() -> TypeBuilder {
TypeBuilder { s: "".to_string() }
}
fn s(&mut self, s: String) -> &mut TypeBuilder {
self.s = s;
self
}
fn finalize(&self) -> Type {
Type { s: &self.s }
}
}
fn main() {
let t = TypeBuilder::new()
.s("a".to_string())
.finalize();
println!("string: {}", t.s);
}
The problem is that you're creating Type with a string slice based on a String from TypeBuilder, but TypeBuilder instance created with new() is destroyed immediately in the same let statement, so if this was allowed, the string slice would became dangling. And that's why it works when you store TypeBuilder in a variable first.
The problem with your approach to the builder is that the builder is the owner of data for the value it builds: Type references the contents of TypeBuilder. This means that Type instances are always tied to TypeBuilder instances, and you just cannot create Type and drop TypeBuilder. However, this is really unnatural - builders are usually transient objects which are only necessary during construction.
Consequently, in order for the builder pattern to work correctly your Type must become the owner of the data:
struct Type {
s: String,
}
Then the builder should be passed by value and then consumed by finalize():
impl TypeBuilder {
fn new() -> TypeBuilder {
TypeBuilder { s: "".to_string() }
}
fn s(mut self, s: String) -> TypeBuilder {
self.s = s;
self
}
fn finalize(self) -> Type {
Type { s: self.s }
}
}
This way your building code should work exactly as it is.