What does Some() do on the left hand side of a variable assignment? - syntax

I was reading some Rust code and I came across this line
if let Some(path) = env::args().nth(1) {
Inside of this function
fn main() {
if let Some(path) = env::args().nth(1) {
// Try reading the file provided by the path.
let mut file = File::open(path).expect("Failed reading file.");
let mut content = String::new();
file.read_to_string(&mut content);
perform_conversion(content.as_str()).expect("Conversion failed.");
} else {
println!(
"provide a path to a .cue file to be converted into a MusicBrainz compatible tracklist."
)
}
}
The line seems to be assigning the env argument to the variable path but I can't work out what the Some() around it is doing.
I took a look at the documentation for Option and I understand how it works when used on the right hand side of = but on the left hand side I am a little confused.
Am I right in thinking this line is equivalent to
if let path = Some(env::args().nth(1)) {

From the reference :
An if let expression is semantically similar to an if expression but
in place of a condition expression it expects the keyword let followed
by a refutable pattern, an = and an expression. If the value of the
expression on the right hand side of the = matches the pattern, the
corresponding block will execute, otherwise flow proceeds to the
following else block if it exists. Like if expressions, if let
expressions have a value determined by the block that is evaluated.
In here the important part is refutability. What it means refutable pattern in here it can be in different forms. For example :
enum Test {
First(String, i32, usize),
Second(i32, usize),
Third(i32),
}
You can check the x's value for a value for 3 different pattern like :
fn main() {
let x = Test::Second(14, 55);
if let Test::First(a, b, c) = x {}
if let Test::Second(a, b) = x {} //This block will be executed
if let Test::Third(a) = x {}
}
This is called refutability. But consider your code like this:
enum Test {
Second(i32, usize),
}
fn main() {
let x = Test::Second(14, 55);
if let Test::Second(a, b) = x {}
}
This code will not compile because x's pattern is obvious, it has single pattern.
You can get more information from the reference of refutability.
Also you are not right thinking for this:
if let path = Some(env::args().nth(1)) {
Compiler will throw error like irrefutable if-let pattern because as the reference says: "keyword let followed by a refutable pattern". In here there is no refutable pattern after "let". Actually this code tries to create a variable named path which is an Option and this make no sense because there is no "If" needed,
Instead Rust expects from you to write like this:
let path = Some(env::args().nth(1)); // This will be seem like Some(Some(value))

The other answers go into a lot of detail, which might be more than you need to know.
Essentially, this:
if let Some(path) = env::args().nth(1) {
// Do something with path
} else {
// otherwise do something else
}
is identical to this:
match env::args().nth(1) {
Some(path) => { /* Do something with path */ }
_ => { /* otherwise do something else */ }
}

Related

Rust proc_macro_derive (with syn crate) generating enum variant for matching

I'm a rust newbie, I started one week ago but this language is already very exciting. I'm rewritting a nodejs project in rust to get better performance and for the moment it's just crazy how faster it is.
I'm actually writting a proc_derive_macro (using the "syn" crate) to generate method on some specific struct. I'm almost done but i don't find how to generate enum variant. I will try to explain myself.
That's my code generation (using quote!)
quote! {
// The generated impl.
impl #name /*#ty_generics #where_clause*/ {
pub fn from_config(config: &IndicatorConfig) -> Result<Self, Error> {
let mut #name_lower = #name::default()?;
for (k, v) in config.opts.iter() {
println!("{:?} {:?}", k, v);
match (k.as_str(), v) {
("label", Values::String(val)) => {
#name_lower.label = val.clone();
}
("agg_time", Values::String(val)) => {
#name_lower.agg_time = Some(val.clone());
}
#(
(#fields_name_str, Values::Unteger(val)) => {
#name_lower.#fields_name = val.clone();
}
)*
(&_, _) => {}
}
}
#name_lower.init()?;
Ok(#name_lower)
}
}
};
As we can see I'm generating much of my code here
(#fields_name_str, Values::Unteger(val)) => {
#name_lower.#fields_name = val.clone();
}
But I didn't find a way to generate an "enum variant for the matching" (I don't know how we call that, i hope you will understand):
Values::String(val)
OR
Values::Unteger(val)
...
I'm writting a function which will create the variant matching according to parameter type found inside the struct:
fn create_variant_match(ty: &str) -> PatTupleStruct {
let variant = match ty {
"u32" => Ident::new("Unteger", Span::call_site()),
...
_ => unimplemented!(),
};
}
Actually I'm creating an Ident but I want to create the "enum variant match" -> Values::Unteger(val).
I watched the doc of the syn crate, spend hours trying to find a way, but it's a bit complex for my actual level, so I hope someone will explain me how to do that.
I found a simple way of doing that. Just need to parse a string (which i can format before) using the syn parser.
Didn't think about it before was trying to construct the Expr by hand (a bit stupid ^^)
syn::parse_str::<Expr>("Values::Unteger(val)")
which will generate the Expr needed

Referencing / dereferencing a vector element in a for loop

In the code below, I want to retain number_list, after iterating over it, since the .into_iter() that for uses by default will consume. Thus, I am assuming that n: &i32 and I can get the value of n by dereferencing.
fn main() {
let number_list = vec![24, 34, 100, 65];
let mut largest = number_list[0];
for n in &number_list {
if *n > largest {
largest = *n;
}
}
println!("{}", largest);
}
It was revealed to me that instead of this, we can use &n as a 'pattern':
fn main() {
let number_list = vec![24, 34, 100, 65];
let mut largest = number_list[0];
for &n in &number_list {
if n > largest {
largest = n;
}
}
println!("{}", largest);
number_list;
}
My confusion (and bear in mind I haven't covered patterns) is that I would expect that since n: &i32, then &n: &&i32 rather than it resolving to the value (if a double ref is even possible). Why does this happen, and does the meaning of & differ depending on context?
It can help to think of a reference as a kind of container. For comparison, consider Option, where we can "unwrap" the value using pattern-matching, for example in an if let statement:
let n = 100;
let opt = Some(n);
if let Some(p) = opt {
// do something with p
}
We call Some and None constructors for Option, because they each produce a value of type Option. In the same way, you can think of & as a constructor for a reference. And the syntax is symmetric:
let n = 100;
let reference = &n;
if let &p = reference {
// do something with p
}
You can use this feature in any place where you are binding a value to a variable, which happens all over the place. For example:
if let, as above
match expressions:
match opt {
Some(1) => { ... },
Some(p) => { ... },
None => { ... },
}
match reference {
&1 => { ... },
&p => { ... },
}
In function arguments:
fn foo(&p: &i32) { ... }
Loops:
for &p in iter_of_i32_refs {
...
}
And probably more.
Note that the last two won't work for Option because they would panic if a None was found instead of a Some, but that can't happen with references because they only have one constructor, &.
does the meaning of & differ depending on context?
Hopefully, if you can interpret & as a constructor instead of an operator, then you'll see that its meaning doesn't change. It's a pretty cool feature of Rust that you can use constructors on the right hand side of an expression for creating values and on the left hand side for taking them apart (destructuring).
As apart from other languages (C++), &n in this case isn't a reference, but pattern matching, which means that this is expecting a reference.
The opposite of this would be ref n which would give you &&i32 as a type.
This is also the case for closures, e.g.
(0..).filter(|&idx| idx < 10)...
Please note, that this will move the variable, e.g. you cannot do this with types, that don't implement the Copy trait.
My confusion (and bear in mind I haven't covered patterns) is that I would expect that since n: &i32, then &n: &&i32 rather than it resolving to the value (if a double ref is even possible). Why does this happen, and does the meaning of & differ depending on context?
When you do pattern matching (for example when you write for &n in &number_list), you're not saying that n is an &i32, instead you are saying that &n (the pattern) is an &i32 (the expression) from which the compiler infers that n is an i32.
Similar things happen for all kinds of pattern, for example when pattern-matching in if let Some (x) = Some (42) { /* … */ } we are saying that Some (x) is Some (42), therefore x is 42.

How do I remove the \\?\ prefix from a canonical Windows path?

On Windows, Path::canonicalize() returns the path in the format:
\\\\?\\C:\\projects\\3rdparty\\rust...
This is because it is the correct canonical path, and allows 'long' paths on Windows (see Why does my canonicalized path get prefixed with \\?\).
However, this is not a user-friendly path, and people do not understand it.
For display and logging purposes how can I easily remove this prefix in a generic platform independent way?
Path::components will return a component \\?\C: as the first component...
Should I convert this to a &str and use a regex? Is there some other more ergonomic method for removing the prefix, e.g. some type with a Display implementation that automatically does the right thing?
My requirements specifically are:
Correctly displays X:\\... for a canonical path on Windows.
Doesn't screw up non-Windows platforms (e.g. strip or change path components)
Example:
use std::path::{Path, PathBuf};
fn simple_path<P: AsRef<Path>>(p: P) -> String {
String::from(p.as_ref().to_str().unwrap()) // <-- ?? What to do here?
}
pub fn main() {
let path = PathBuf::from("C:\temp").canonicalize().unwrap();
let display_path = simple_path(path);
println!("Output: {}", display_path);
}
Use the dunce crate:
extern crate dunce;
…
let compatible_path = dunce::canonicalize(&any_path);
Just stripping \\?\ may give wrong/invalid paths. The dunce crate checks whether the UNC path is compatible and converts the path accurately whenever possible. It passes through all other paths. It compiles to plain fs::canonicalize() on non-Windows.
The straightforward answer is to do platform-specific string munging:
use std::path::{Path, PathBuf};
#[cfg(not(target_os = "windows"))]
fn adjust_canonicalization<P: AsRef<Path>>(p: P) -> String {
p.as_ref().display().to_string()
}
#[cfg(target_os = "windows")]
fn adjust_canonicalization<P: AsRef<Path>>(p: P) -> String {
const VERBATIM_PREFIX: &str = r#"\\?\"#;
let p = p.as_ref().display().to_string();
if p.starts_with(VERBATIM_PREFIX) {
p[VERBATIM_PREFIX.len()..].to_string()
} else {
p
}
}
pub fn main() {
let path = PathBuf::from(r#"C:\Windows\System32"#)
.canonicalize()
.unwrap();
let display_path = adjust_canonicalization(path);
println!("Output: {}", display_path);
}
For the record, I don't agree that your premise is a good idea. Windows Explorer handles these verbatim paths just fine, and I think users are capable of handling it as well.
For [...] logging purposes
This sounds like a terrible idea. If you are logging something, you want to know the exact path, not some potentially incorrect path.
Here's a version that reconstructs the path from the components.
It helps with std::fs::canonicalize on Windows, but a naive Path::new(r"\\?\C:\projects\3rdparty\rust") at play.rust-lang.org will produce a single-component Path.
use std::path::{Component, Path, PathBuf, Prefix};
// Should remove the “\\?” prefix from the canonical path
// in order to avoid CMD bailing with “UNC paths are not supported”.
let head = path.components().next().ok_or("empty path?")?;
let diskˢ;
let head = if let Component::Prefix(prefix) = head {
if let Prefix::VerbatimDisk(disk) = prefix.kind() {
diskˢ = format!("{}:", disk as char);
Path::new(&diskˢ).components().next().ok_or("empty path?")?
} else {
head
}
} else {
head
};
println!("{:?}", head);
let path = std::iter::once(head)
.chain(path.components().skip(1))
.collect::<PathBuf>();

Type 'Double' does not conform to protocol 'Sequence Type'

This is my code and I don't know why it's not working. The title is what the error says. I'm working with Swift in Xcode and the code is supposed to create a function with as many parameters as I tell it to have/unlimited.
func addMyAccountBalances(balances : Double) -> Double {
var result : Double = 0
for balance in balances {
result += balance
}
}
the code is supposed to create a function with as many parameters as i tell it
What you probably want is a function taking a variable number of arguments,
this is indicated by ... following the type:
func addMyAccountBalances(balances : Double ...) -> Double {
var result : Double = 0
for balance in balances {
result += balance
}
return result
}
print(addMyAccountBalances(1.0, 2.0, 3.0))
print(addMyAccountBalances(4.5, 5.6))
Inside the function, balances has the array type [Double] so that
you can iterate over its elements.
Note that this can be written more compactly with reduce():
func addMyAccountBalances(balances : Double ...) -> Double {
let result = balances.reduce(0.0, combine: +)
return result
}
Your code does not compile because balances : Double is just
a double number, not an array or sequence.

What does the rust compiler "error: can't capture dynamic environment in a fn item; use the || { ... } closure form instead" mean, and how to fix it?

I get a rust compiler error:
src/main.rs:33:31: 33:35 error: can't capture dynamic environment in a fn item; use the || { ... } closure form instead
The error occurs because I have a function in which I declare a variable using let, and then have an inner function in which I try to use this variable that is closed over.
I am fairly certain that this is a beginner question, so sorry in advance if this has a very straight forward answer!
Note that I am using this inner function as a callback somewhere, and thus using a closure, like
let closure_fn = | args | -> () { do stuff };
... is not going to be an appropriate solution for me.
extern crate nickel;
use std::io::net::ip::Ipv4Addr;
use nickel::{ Nickel, Request, Response };
fn stub_3rd_party_function() -> String {
"hello world".to_string()
}
fn main() {
let mut server = Nickel::new();
// assume that the variable **must** be instantiated like this
let hello_text : String = stub_3rd_party_function();
fn hello_handler (_request: &Request, response: &mut Response) -> () {
response.send(hello_text.as_slice());
}
server.get("/hello", hello_handler);
server.listen(Ipv4Addr(0,0,0,0), 6767);
}
Results in the following error:
src/test.rs:12:23: 12:33 error: can't capture dynamic environment in a fn item; use the || { ... } closure form instead
src/test.rs:12 response.send(hello_text);
^~~~~~~~~~
src/test.rs:12:23: 12:33 error: unresolved name `hello_text`.
src/test.rs:12 response.send(hello_text);
^~~~~~~~~~
error: aborting due to 2 previous errors
Now, I switch from a standard function to a closure function instead:
extern crate nickel;
use std::io::net::ip::Ipv4Addr;
use nickel::{ Nickel, Request, Response };
fn stub_3rd_party_function() -> String {
"hello world".to_string()
}
fn main() {
let mut server = Nickel::new();
// assume that the variable **must** be instantiated like this
let hello_text : String = stub_3rd_party_function();
let hello_handler = |_request: &Request, response: &mut Response| -> () {
response.send(hello_text.as_slice());
};
server.get("/hello", hello_handler);
server.listen(Ipv4Addr(0,0,0,0), 6767);
}
Results in a different error:
src/test.rs:21:30: 21:43 error: mismatched types: expected `fn(&nickel::request::Request<'_>, &mut nickel::response::Response<'_,'_>)` but found `|&nickel::request::Request<'_>, &mut nickel::response::Response<'_,'_>|` (expected extern fn but found fn)
src/test.rs:21 server.get("/hello", hello_handler);
^~~~~~~~~~~~~
error: aborting due to previous error
Is there perhaps a way to "wrap" the closed over function with a normal one?
Since the library that I am using expects a standard function instead of a closure,
I cannot use a closure.
But if I do not use a closure, I cannot close over variables that are defined within the outer function, fn main () { ... }... and thus getting stuck here.
Note that above, I am using a string, hello_text, for the purposes of providing a concise code example.
In this case using a static variable would suffice. However, static variables will not fix it for me, as I need to be able to assign a variable from within a fn main() the result of a function call, and then use that within my inner handler function.
It says that because it’s the simple truth: a function cannot capture variables; if you put a function inside another function, that the function is inside the function rather than outside is purely a matter of namespacing and making it absolutely private and inaccessible to anything else. If you want such variable capturing, you must use a closure.
In your specific case, functions are the only way. You should consider your code to be this (I would write it this way, too, to reduce indentation if nothing else):
fn hello_handler(_request: &Request, response: &mut Response) {
response.send(hello_text);
}
fn main() {
let mut server = Nickel::new();
let hello_text = "hello world";
server.get("/hello", hello_handler);
server.listen(Ipv4Addr(0, 0, 0, 0), 6767);
}
As you can see with this way of expressing it, hello_text is evidently inaccessible from hello_handler. There are sound technical reasons why it must be so, also—each request is handled in its own task. In this particular case, a static is the solution:
static HELLO_TEXT: &'static str = "hello world";

Resources