I'm attempting to merge a JSON string as Vec<u8> with the result of decoding a Base64VecU8 value:
pub fn decode_and_merge(&mut self, args: Base64VecU8) {
// This unwraps correctly
let args_des: Vec<u8> = serde_json::to_string(&args).unwrap().into_bytes();
// This also returns a Vec<u8>
let args_des = args.0;
// But when trying to extend, append or merge:
let init_fn_args = [
Into::<Vec<u8>>::into(args_des)[..],
serde_json::json!({ "market_creator_account_id": env::signer_account_id() })
.to_string()
.into_bytes()[..],
];
let promise = Promise::new("cc".to_string())
.create_account()
.deploy_contract(MARKET_CODE.to_vec())
.transfer(env::attached_deposit())
.function_call(
"new".to_string(),
init_fn_args, // FAILS with expected struct `std::vec::Vec`, found array `[[u8]; 2]`
0,
GAS_FOR_CREATE_MARKET,
);
// Also tried with
let init_fn_args = args_des.extend(
serde_json::json!({ "market_creator_account_id": env::signer_account_id() })
.to_string()
.into_bytes(),
);
let promise = Promise::new("cc".to_string())
.create_account()
.deploy_contract(MARKET_CODE.to_vec())
.transfer(env::attached_deposit())
.function_call(
"new".to_string(),
init_fn_args, // FAILS with expected struct `std::vec::Vec`, found `()`
0,
GAS_FOR_CREATE_MARKET,
);
}
The most confusing part is expected struct 'std::vec::Vec', found '()'. I still don't understand why it results in () instead of the Vec
The full compiler errors for the first attempt:
error[E0308]: mismatched types
--> src/contract.rs:69:47
|
69 | .function_call("new".to_string(), init_fn_args, 0, GAS_FOR_CREATE_MARKET);
| ^^^^^^^^^^^^ expected struct `Vec`, found array `[[u8]; 2]`
|
= note: expected struct `Vec<u8>`
found array `[[u8]; 2]`
The full compiler errors for the second attempt:
error[E0308]: mismatched types
--> src/contract.rs:69:47
|
69 | .function_call("new".to_string(), init_fn_args, 0, GAS_FOR_CREATE_MARKET);
| ^^^^^^^^^^^^ expected struct `Vec`, found `()`
|
= note: expected struct `Vec<u8>`
found unit type `()`
The first version didn't work because [...] creates an array, not a Vec. To fix it, you should use vec![...] instead.
The second version didn't work because Vec::extend() works by side effect and therefore doesn't return a value. (This is very much like Python where list.append or list.sort return None.) To fix it, you should call args_des.extend(...whatever...) and then use args_des instead of init_fn_args (or declare a let init_fn_args = args_des; after the call to extend()).
Thanks for your answers, what finally worked is this:
pub fn merge(&mut self, args: Base64VecU8) -> Promise {
let mut init_args: Value = serde_json::from_slice(&args.0.as_slice()).unwrap();
init_args.as_object_mut().unwrap().insert(
"another_arg".to_string(),
Value::String(env::signer_account_id().to_string()),
);
// ...
Related
I have a closure that looks like this:
pub fn getBytes(bytes: Vec<String>) -> Result(String, InputError) {
bytes.iter().for_each(|byte| {
let mut fixed_byte = String::new();
if byte.contains("0x") {
fixed_byte = dict::add_push(byte);
if fixed_byte.trim() == String::from("Wrong length") {
return Err(InputError::WrongHexLength(byte.to_string())); // Problem is here
}
}
bytecode.push_str(&fixed_byte);
});
Ok(bytecode)
}
And I want to return a custom error, but since it's inside a closure I get an error like this:
mismatched types
--> src/lib.rs:110:24
|
110 | return Err(InputError::WrongHexLength(byte.to_string()))
;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
expected `()`, found enum `Result`
|
= note: expected unit type `()`
found enum `Result<_, InputError>`
How can I terminate what the closure does and just return the error?
Thanks!
Use try_for_each. As documentation says:
An iterator method that applies a fallible function to each item in the iterator, stopping at the first error and returning that error.
Alternatively use for loop and more imperative approach instead of functional for_each.
mystring.rs
pub fn return_string() {
return "Some String"
}
then in main, I want to print this string
mod mystring;
const test = config::return_string();
println!("{}", test);
the error I get is
println!("{}", test);
| ^^^^ `()` cannot be formatted with the default formatted
I assume that your minimal reproducible example is:
pub fn return_string() {
return "Some String"
}
fn main() {
const test = return_string();
println!("{}", test);
}
error: missing type for `const` item
--> src/main.rs:6:11
|
6 | const test = return_string();
| ^^^^ help: provide a type for the constant: `test: ()`
error[E0308]: mismatched types
--> src/main.rs:2:12
|
1 | pub fn return_string() {
| - help: try adding a return type: `-> &'static str`
2 | return "Some String"
| ^^^^^^^^^^^^^ expected `()`, found `&str`
error[E0277]: `()` doesn't implement `std::fmt::Display`
--> src/main.rs:7:20
|
7 | println!("{}", test);
| ^^^^ `()` cannot be formatted with the default formatter
|
= help: the trait `std::fmt::Display` is not implemented for `()`
= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
= note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
Solution
There are two errors in your code:
don't use const inside of functions. Use let. let is an immutable value. let mut would be mutable. const is only used for immutable globals.
you are missing the return type for your return_string() function
I'll assume here that the return type is &str, but it might as well have to be String. For more info search for &str vs String.
Third, as a minor annotation, avoid return as much as possible, if not required. The last line of a function is automatically the return type if you don't finish it with ;.
pub fn return_string() -> &'static str {
"Some String"
}
fn main() {
let test = return_string();
println!("{}", test);
}
Some String
Explanation of the error message
The error message says that () is not printable.
() is the empty type, analogous to void in C++. As you don't annotate the return type of return_string(), Rust assumes it's (). And () cannot be printed directly, at least not with the Display formatter.
You could print it with the Debug formatter, though:
pub fn return_void() {}
fn main() {
let test = return_void();
println!("{:?}", test);
}
()
Note that contrary to C++, () is actually a storable type, even if it is of size 0 with no data in it. That makes things a lot easier for generics. C++ templates that need to be able to deal with void return values were a major pain factor for me in the past, as they always required a special case.
I defined a function for postgresql pagination query like this:
pub fn fav_music_query<T>() -> Paginated<T> {
use crate::model::diesel::rhythm::rhythm_schema::favorites::dsl::*;
let connection = config::establish_music_connection();
let query = favorites.filter(like_status.eq(1)).paginate(1).per_page(10);
let query_result = query.load_and_count_pages::<Favorites>(&connection).unwrap();
let page_result = Paginated{
query: query_result.0,
page: 1,
per_page: 10,
is_sub_query: false
};
return page_result;
}
when I use this code to invoke the function:
let dashboards = fav_music_query::<Vec<Favorites>>();
it shows this error:
error[E0308]: mismatched types
--> src/service/home/home_service.rs:18:12
|
6 | pub fn fav_music_query<T>() -> Paginated<T> {
| - ------------ expected `Paginated<T>` because of return type
| |
| this type parameter
...
18 | return page_result;
| ^^^^^^^^^^^ expected type parameter `T`, found struct `Vec`
|
= note: expected struct `Paginated<T>`
found struct `Paginated<Vec<Favorites>>`
what should I do to fix it? Vec<> not a T generic type?
Vec<?> would be a valid option for T, but the issue is that it always attempts to return a Vec<Favorites> regardless of if the requested T is a Vec or not.
It is complaining because the function signature declares that it returns a generic, but the function implementation always attempts to return the same type.
// For example, according to the function signature I should be able to do this
let bar: Foo = fav_music_query<Foo>();
Now what I assume you want to do is have the function return a generic Paginated result. That isn't too difficult to do, we just need to replace the hard coded type with our generic and tweak the signature to match the result of load_and_count_pages() when we request our generic T from it. That being said, you will probably run into some errors with load_and_count_pages having bounds on the generic T which you will have to apply to the function signature fav_music_query<T: SomeBounds + OtherBounds>().
// Tweak the signature to follow expected result of load_and_count_pages
pub fn fav_music_query<T>() -> Paginated<Vec<T>> {
use crate::model::diesel::rhythm::rhythm_schema::favorites::dsl::*;
let connection = config::establish_music_connection();
let query = favorites.filter(like_status.eq(1)).paginate(1).per_page(10);
// Change Faborites to T so the generic is used instead of a hardcoded type
let query_result = query.load_and_count_pages::<T>(&connection).unwrap();
let page_result = Paginated{
query: query_result.0,
page: 1,
per_page: 10,
is_sub_query: false
};
return page_result;
}
Alternatively, if you only want Paginated<Vec<Favorites>>, you could just remove the generic entirely and it should work just fine.
pub fn fav_music_query() -> Paginated<Vec<Favorites>> { ... }
test2.json
[
{"name":"Lucy","age":18,"achievement":[95,86.5,90]},
{"name":"Lily","age":19,"achievement":[92.5,89,91]},
{"name":"Jack","age":20,"achievement":[93,90,93.5]}
]
main.rs
use std::fs::File;
use std::io::BufReader;
use serde_json::{Result as SResult, Value};
fn get_profile() -> SResult<Value> {
let file = File::open("test2.json").expect("file should open read only");
let reader = BufReader::new(file);
let mut v: Value = serde_json::from_reader(reader)?;
Ok(v.take())
}
fn main() {
let profiles = get_profile().unwrap();
for element in profiles.as_array().iter() {
println!("the value is: {}", element["age"]);
}
}
error:
λ cargo run
Compiling hello-rust v0.1.0 (D:\workspace\rust-projects\hello-rust)
error[E0277]: the type `[Value]` cannot be indexed by `&str`
--> src\main.rs:20:38
|
20 | println!("the value is: {}", element["age"]);
| ^^^^^^^^^^^^^^ slice indices are of type `usize` or ranges of `usize`
|
= help: the trait `SliceIndex<[Value]>` is not implemented for `&str`
= note: required because of the requirements on the impl of `std::ops::Index<&str>` for `Vec<Value>`
For more information about this error, try `rustc --explain E0277`.
error: could not compile `hello-rust` due to previous error
How to fix the issue?
Any help please, thanks.
You are calling .iter() on an Option<&Vec<Value>>. The iterator yields one value if the Option is a Some, otherwise none.
You can change your loop to this instead, which will yield one Value (here the object) at a time:
for element in profiles.as_array().unwrap().iter() {
println!("the value is: {}", element["age"]);
}
Note: I'd at least use is_array() etc. to validate the structure and improve error handling (not just unwrap(). You get a lot for free when using structs and Deserialize instead of parsing everything manually.
Example:
#[derive(Deserialize)]
struct Profile {
name: String,
age: usize,
achievement: Vec<f64>,
}
let profiles: Vec<Profile> =
serde_json::from_reader(BufReader::new(File::open("test2.json").unwrap())).unwrap();
for profile in profiles {
println!("the value is: {}", profile.age);
}
I am a bit puzzled by why dereferencing a &&str doesn't seem to work in the second case:
use std::collections::HashSet;
fn main() {
let days = vec!["mon", "tue", "wed"];
let mut hs: HashSet<String> = HashSet::new();
for d in &days {
// works
hs.insert(String::from(*d));
// doesn't
hs.insert(*d.to_string());
}
println!("{:#?}", hs);
}
str does implement a ToString trait, but it still gives me the error:
error[E0308]: mismatched types
--> src/main.rs:12:19
|
12 | hs.insert(*d.to_string());
| ^^^^^^^^^^^^^^ expected struct `std::string::String`, found str
|
= note: expected type `std::string::String`
found type `str`
What syntax am I getting wrong here?
Rust Playground Link
to_string is called to d before it's deref'd, so you will deref the String, which results in str.
Change it to
hs.insert(d.to_string());
This works because d is automatically deref'd to str, which will be converted into String afterwards. This is called Deref coercions.
If you have a type U, and it implements Deref<Target=T>, values of &U will automatically coerce to a &T
...
Deref will also kick in when calling a method
This is exactly the case here: impl Deref<Target = str> for String. See here for an example:
A value of type &&&&&&&&&&&&&&&&Foo can still have methods defined on Foo called, because the compiler will insert as many * operations as necessary to get it right. And since it’s inserting *s, that uses Deref.
This example demonstrates this:
struct Foo;
impl Foo {
fn foo(&self) { println!("Foo"); }
}
let f = &&Foo;
// prints "foo"
f.foo();
By the way,
hs.insert((*d).to_string());
will also work, since it's first deref'd to &str.