I'm declaring a HashMap in Java 8, this:
HashMap<String, String> nameMap = new HashMap<>();
OR
HashMap<String, String> nameMap = new HashMap<String, String>();
The compiler show this error: unreachable code. When I put HashMap<String, Object> nameMap = new HashMap<>() this error disapears.
Not possible only.
1) Check ur compiler . Should be using correct version 1.8 even if u added jdk 1.8. I think for u this is set as 1.5 coz diamond operator (<>) was introduced in 1.7 I think.
Related
This question already has an answer here:
Returning a default &str for HashMap<_, String> [duplicate]
(1 answer)
Closed 9 months ago.
So this is my situation:
let map: HashMap<String, String> = HashMap::new();
let key = String::from("key");
let v = map.get(&key).unwrap_or(&String::from("key not found"));
println!("{}", v);
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=1cab10de5528149c5d4ac37d9e0964f0
And this is my error:
temporary value is freed at the end of this statement creates a temporary which is freed while still in use
Being quite new to Rust I'm not sure if I'm using String properly or if str or &str would be more appropriate, but in any case I'm not exactly sure how I could use unwrap_or in this case to return a reference to a String. I know I could use pattern matching but I would prefer this pattern.
How do I use unwrap_or to return a string reference?
Short answer: you do not unless is a &'static str
For your case, you are creating an String already, so return a String and then use it whenever you need the &str. Also as nitpick, you would probably should use unwrap_or_else to avoid allocating the String in case the item is found:
let map: HashMap<String, String> = HashMap::new();
let v = map.get(&key).unwrap_or_else(|| String::from("key not found"));
println!("{}", v);
I am trying to evaluate a string in rust with conditionals using evalexpr module.
This results in the following error
thread 'main' panicked at 'called Result::unwrap() on an Err value: AppendedToLeafNode', src\main.rs:6:56
The error description says
https://docs.rs/evalexpr/5.0.5/evalexpr/error/enum.EvalexprError.html#variant.AppendedToLeafNode
Tried to append a child to a leaf node. Leaf nodes cannot have
children.
I am not able to understand why this error is happening. Does anyone have a clue? Is it possible to evaluate an string with conditionals in Rust?
use evalexpr::*;
fn main() {
let evalstr = "let x = if input == 8 { 3 } else { 4 };";
let mut context = HashMapContext::new();
context.set_value("input".into(), 8.into()).unwrap();
eval_empty_with_context_mut(evalstr, &mut context).unwrap();
let val = context.get_value("x").unwrap();
println!("{}", val);
}
evalexpr doesn't support the Rust language, but uses its own little language documented here: https://docs.rs/evalexpr/6.6.0/evalexpr/index.html#features
That little language does not support conditionals yet: https://github.com/ISibboI/evalexpr/issues/82
We have a HashMap, over which we iterate and map to replace the values, but are running into an issue collecting that back to a new HashMap with different value type.
value of type `std::collections::HashMap<std::string::String, std::string::String>`
cannot be built from `std::iter::Iterator<Item=(&std::string::String, std::string::String)>`
What we are doing essentially boils down to this:
let old: HashMap<String, Value> = some_origin();
let new: HashMap<String, String> = old.iter().map(|(key, value)| {
return (key, some_conversion(value));
}).collect();
The same iterator type is also returned (and not collectable), if one zips two iterators, e.g. in this case zipping key, and the map that only returns the converted value.
new = old.keys().into_iter().zip(old.iter().map(|(key, value)| some_conversion(value)).collect();
The issue is that iter() (docs) returns a 'non-consuming' iterator which hands out references to the underlying values ([1]). The new HashMap cannot be constructed using references (&String), it needs values (String).
In your example, some_conversion seems to return a new String for the value part, so applying .clone() to the key would do the trick:
let old: HashMap<String, Value> = some_origin();
let new: HashMap<String, String> = old.iter().map(|(key, value)| {
return (key.clone(), some_conversion(value));
// ^---- .clone() call inserted
}).collect();
Here is a link to a full example on the rust playground.
Looking at the error message from the compiler [2], this is indeed quite hard to figure out. I think what most helps with this is to build up an intuition around references and ownership in Rust to understand when references are OK and when an owned value is needed.
While I'd recommend reading the sections on references and ownership in the Rust Book and even more Programming Rust, the gist is as follows:
Usually, values in Rust have exactly one owner (exceptions are explicit shared ownership pointers, such as Rc).
When a value is passed 'by value' it is moved to the new location. This invalidates the original owner of the value.
There can be multiple shared references to a value, but while any shared reference exists, the value is immutable (no mutable references can exist or be created, so it cannot be modified or moved).
We cannot move a value out of a shared reference (this would invalidate the original owner, which is immutable while a shared reference exists).
Usually, Rust doesn't automatically copy (in Rust parlance "clone") values, even if it could. Instead it takes ownership of values. (The exception are "Copy" types which are cheap to copy, such as i32).
(Not relevant here) There can also be a single mutable reference to a value. While this mutable reference exits no shared references can be created.
How does this help?
Who owns the keys in the hash map? The hash map does (rule 1)!
But how do we get a new key-value pair into the hash map? The values are moved into the hash map (rule 2).
But we can't move out of a shared reference ... (rule 3 + rule 4)
And Rust doesn't want to clone the value unless we tell it to do so (rule 5)
... so we have to clone it ourselves.
I hope this gives some intuition (again I would really recommend Programming Rust on this). In general, if you do something with a value, you either take ownership over it, or you get a reference. If you take ownership, the original variable that had ownership can no longer be used. If you get a reference, you can't hand ownership to somebody else (without cloning). And Rust doesn't clone for you.
[1]: The docs call this "An iterator visiting all key-value pairs in arbitrary order. The iterator element type is (&'a K, &'a V)." Ignoring the 'a lifetime parameters, you can see that the element type is (&K, &V).
[2]:
13 | .collect();
| ^^^^^^^ value of type `std::collections::HashMap<std::string::String, std::string::String>` cannot be built from `std::iter::Iterator<Item=(&std::string::String, std::string::String)>`
|
= help: the trait `std::iter::FromIterator<(&std::string::String, std::string::String)>` is not implemented for `std::collections::HashMap<std::string::String, std::string::String>`
If you don't need the old map any more you can just use into_iter.
let new: HashMap<String, String> = old.into_iter().map(|(key, value)| {
return (key, some_conversion(value));
}).collect();
You can see a working version here
The following C# code compiles fine:
static readonly List<int> list = new List<int>();
static void Main(string[] args)
{
list.Add(1);
list.Add(2);
list.Add(3);
}
If I write similar code in Rust, it won't compile because it cannot borrow immutable v as mutable:
let v = Vec::new();
v.push(1);
v.push(2);
v.push(3);
How does the push function know v is immutable?
All variables are immutable by default. You must explicitly tell the compiler which variables are mutable though the mut keyword:
let mut v = Vec::new();
v.push(1);
v.push(2);
v.push(3);
Vec::push is defined to require a mutable reference to the vector (&mut self):
fn push(&mut self, value: T)
This uses method syntax, but is conceptually the same as:
fn push(&mut Vec<T>, value: T)
I highly recommend that you read The Rust Programming Language, second edition. It covers this beginner question as well as many other beginner questions you will have.
In Rust, bindings are immutable by default. So you might think that the following are equivalent:
readonly List<int> list = new List<int>(); // C#
let list = Vec::new(); // Rust
And these:
List<int> list = new List<int>(); // C#
let mut list = Vec::new(); // Rust
But, as you found out, this isn't quite the case.
Inside the Add method in the C# version, there is no information about the binding that you used to invoke it. The Add method isn't able to declare that it mutates its data so there is no way for the C# compiler to prevent you passing a reference to a readonly binding. The readonly keyword prevents you overwriting the list binding with a completely new List, but it doesn't prevent you changing data inside the one you have. C# prevents you from changing the value of a readonly binding, but the value in this case is a pointer to your data, not the data itself.
In Rust, if a method needs to mutate the underlying data, it must declare its first argument to be self or &mut self.
In the case of self, then the data is moved into the method, and you can no longer use the original binding. It doesn't matter if the method changes the data because the caller can't use that binding any more.
In the case of a mutable reference, &mut self, Rust will only let you create it if the original binding is also mutable. If the original binding is immutable then this will produce a compile error. It is impossible to call v.push if v is immutable, because push expects &mut self.
This can be restrictive, so Rust provides tools that let you fine-tune this behaviour to encode exactly the safety guarantees that you need. If you want to get something close to the C# behaviour, you can use a RefCell wrapper (or one of the several other wrapper types). A RefCell<Vec<T>> doesn't itself have to be mutable for functions to be able to unwrap it and modify the Vec inside.
How can I create / allocate an uninitialized fixed sized vector in Rust? Here's how I would do that in Java:
int[] a = new int[128];
This worked:
let a = [0, .. 128];
(via Rust IRC channel)