How to use if let statement with conditions? - rust

I know it's possible to express AND logic between if let statement and a condition like this
if let (Some(a), true) = (b, c == d) {
// do something
}
But what if I need an OR logic?
if let (Some(a)) = b /* || c == d */ {
// do something
} else {
// do something else
}
The only way I figure it out is as follows, but I think it's a little bit ugly as I have to write some code twice
if let (Some(a)) = b {
// do something
} else if c == d {
// do something
} else {
// do something else
}

If you have the same "do something" code in both cases then it must not use a. In that case you can use is_some:
if b.is_some() || c == d {
// do something
} else {
// do something else
}
In the more general case, you can use matches! to check if b matches a pattern without creating any bindings:
if matches!(b, Some(_)) || c == d {
// do something
} else {
// do something else
}

Related

How to get argument of a variant?

Having these enums
pub enum Symbol {
X,
O,
}
pub enum CellContent {
Move(Symbol),
Empty,
}
and
let cell_content = CellContent::Move(Symbol::X);
how can I get the Symbol ? Of course if it's of variant Move(Symbol)
This doesn't work
if cell_0_0 == Move(a_symbol) {
return Some(a_symbol);
}
I cannot also do the following because I must do nothing (code must continue evaluation); and the following doesn't even compile at all !
match cell_0_0 {
Move(symbol) => return symbol;
_ => // do nothing;
}
// code must go on to check further conditions
| I still have some problem with basic syntax of rust, so I'm experiencing making some basic programs
So question is
How to
check if my variable is a variant of Move(Symbol)
if yes return (a copy of) symbol
else do nothing, so code can go on and do more checks
?
Edit 1: Full (not working) code
pub fn some_one_win(&self) -> Option<Symbol> {
let cell_0_0: CellContent = self.table[0][0];
let cell_0_1: CellContent = self.table[0][1];
let cell_0_2: CellContent = self.table[0][2];
if cell_0_0 == cell_0_1 && cell_0_0 == cell_0_2 {
match cell_0_0 {
Move(symbol) => return symbol;
_ => // how to 'do nothing' here ?;
}
}
let cell_1_0: CellContent = self.table[1][0];
let cell_1_1: CellContent = self.table[1][1];
let cell_1_2: CellContent = self.table[1][2];
if cell_1_0 == cell_1_1 && cell_1_0 == cell_1_2 {
match cell_1_0 {
Move(symbol) => return symbol;
_ => // how to 'do nothing' here ?;
}
}
... and so on ..
}
I cannot also do the following because I must do nothing (code must continue evaluation); and the following doesn't even compile at all !
match cell_0_0 {
Move(symbol) => return symbol;
_ => // do nothing;
}
You can do that, if you get the syntax right:
match cell_0_0 {
CellContent::Move(symbol) => {
return Some(symbol);
}
_ => {} // do nothing
}
But as PitaJ mentioned, when there’s only one pattern plus _, the if let construct is usually a cleaner alternative:
if let CellContent::Move(symbol) = cell_0_0 {
return Some(symbol);
}

How to access rust variables outside the scope?

My code look like this
fn main() {
// some other codes goes here
let int = 1;
if int == 1 {
let x = "yes";
} else {
let x = "no";
}
if x == "yes" {
// some other codes goes here
println!("yes");
} else if x == "no" {
// some other codes goes here
println!("no")
}
}
When I run this I get this
error[E0425]: cannot find value `x` in this scope
--> src/main.rs:9:8
|
9 | if x == "yes" {
| ^ not found in this scope
error[E0425]: cannot find value `x` in this scope
--> src/main.rs:12:15
|
12 | } else if x == "no" {
| ^ not found in this scope
While searching for a solution I came across this post How do I access a variable outside of an `if let` expression? but could not able to understand the reason or its solution?
Easiest is by far to code it such that it is in scope in the first place.
You can assign variable with the result of a statement in a single assignment.
If you can make it as a one-liner, it also makes it arguably more readable.
If the actual processing is too long, nothing prevents you from just... making it a proper function.
let x = if int == 1 { "yes" } else { "no" };
// rest of the code accessing x.
Alternatively, the compiler will let you declare unassigned variables if you properly assign them later, with all the compile-time safety checks in place. Read the docs on RAII (Resource Acquisition Is Initialization) RAII Docs to see more how it works. In practice, it's just as simple as this:
let x;
if i == 1 {
x = "yes";
}
else {
x = "no";
}
// keep doing what you love
The compiler will error if there's a logic path where x doesn't get initialized, or if it gets initialized as a different type.
Notice you also do not need to declare it as mut, as the first value it gets will stay immutable. Unless you do want to change it afterwards, obviously.
You can't access a variable which is out of scope. But you use a workaround and set the variable in the same scope.
fn main(){
let int = 1;
let x = if int == 1 {
"yes"
} else {
"no"
};
if x == "yes" {
println!("yes");
} else if x == "no" {
println!("no");
}
}
In Rust each variable has a scope that starts where the variable in initialized. In you problem you try to use the variable x which is created inside of the if int == 1 and the if x == "yes", since if statements have a separate scope from the function main you cannot create a variable inside of your if statement and expect it not to be cleared when you leave scope. The simplest solution is to initialize the variable x where you want to have it used in if x == "yes", so let's say that we want the scope of x to start in main by putting let x; in main. In Rust you may have variable from the larger scope be visible to the scopes that are within that larger scope where the variable in initialized, so assigning the variable from the scope of an if statement is perfectly valid.
Please take a look at https://doc.rust-lang.org/rust-by-example/variable_bindings/scope.html for more information.
fn main() {
let x;
// some other codes goes here
let int = 1;
if int == 1 {
x = "yes";
} else {
x = "no";
}
if x == "yes" {
// some other codes goes here
println!("yes");
} else if x == "no" {
// some other codes goes here
println!("no")
}
}
But you could get rid of the two if statements and just use match:
fn main() {
let myint = 1;
match myint {
1 => {println!("yes")}
_ => {println!("no")}
}
}
The question
I believe you are asking what does this error mean?
To answer that, one must first answer, what is scope?
The answer
Scope, in lay terms, is the section of code where a variable exists.
So when the error says not found in this scope, it means the variable does not exist here.
An example
fn main() {
let a_bool = true;
let main_scope_x = 0;
if a_bool == true {
let if_scope_x = 1;
} // if_scope_x stops existing here!
println!("main x has the value {}", main_scope_x);
println!("if x has the value {}", if_scope_x); // this will cause an error, if_scope_x does not exist outside the if expression.
}
Further info
https://doc.rust-lang.org/stable/book/ch04-01-what-is-ownership.html
(Read the book! It's very good!)

a groovy switch case statement with several variables

Is it possible to have a switch-case statement with more than a variable in groovy? I tried with tuples but the case part doesn't accept more than one argument.
I am trying to avoid several nested if statements so instead of
if (a==1) {
if (b==2) {
if (c==3) {
// do something
}
}
}
else {
if (a==4) {
if (b==5) {
if (c==6) {
//do something else
}
}
}
}
Can I do:
switch(a,b,c) {
case : (1,2,3) // if a==1, b==2 and c==3
// do something
...
case : (4,5,6)
// do something else
...
}
}
Groovy is just dirty java, you don't need any class definition. everything you write in a java method you can write it directly in groovy.
switch (num) {
case 1:
case 2:
case 3:
System.out.println("1 through 3");
break;
case 6:
case 7:
case 8:
System.out.println("6 through 8");
break;
}
To answer your question, inside the switch we need an expression, not function parameters.
Based on your edit, I believe that this should work:
if (a == 1 && b == 2 && c == 3) {
// do something
} else if (a == 4 && b == 5 && c == 6) {
// do something else
}
If you want a switch statement instead, that's possible:
def val = [a, b, c]
switch (val) {
case {it == [1, 2, 3]}:
// something
break;
case {it == [4, 5, 6]}:
// something else
break;
class Solution{
static void main (String...args){
BufferedReader br=new BufferedReader(new
InputStreamReader(System.in))
def val=br.readLine()
switch(val){
case('E0'):
println "Basic"
break;
default:
break;
case('E1'):
println "Inter"
break;
case('E2'):
println "Advance"
break;
default:
println "not defined"
}
}
}

how I could create a metaclass that work with string ; numbers and null values

a metaclass that works with number value string value and null value
like this code ; please help me
String.metaClass.formatx = { delegate.toString().replaceAll(/null/, '0.0').toFloat() }
m= "4".formatx()
m2=4.formatx()
m3=null.formatx()
If I were you, I'd do the following:
String.metaClass.formatx = { -> delegate.toFloat() }
String a = "3"
String b = null
assert 3.0f == (a?.formatx() ?: 0.0f)
assert 0.0f == (b?.formatx() ?: 0.0f)
That is, defend against null in your code with ?. and ?:
If you have to try and catch the null, and format it, you could do:
import org.codehaus.groovy.runtime.NullObject
String.metaClass.formatx = { -> delegate.toFloat() }
NullObject.metaClass.formatx = { -> 0.0f }
String a = "3"
String b = null
assert 3.0f == a.formatx()
assert 0.0f == b.formatx()
But adding a method to NullObject feels wrong, and I've never done it before
Edit
This is shorter
import org.codehaus.groovy.runtime.NullObject
[String, Integer].each { it.metaClass.formatx = { -> delegate.toFloat() } }
NullObject.metaClass.formatx = { -> 0.0f }
println null.formatx()
println 3.formatx()
println "4".formatx()
I put this for example but I think THat I use much code
I repeat metaClass.formatx three times ; I dont know if is possible use OR setences INSTEAD
import org.codehaus.groovy.runtime.NullObject
String.metaClass.formatx = { -> delegate.toString().replaceAll(/null/, '0.0').toFloat() }
NullObject.metaClass.formatx = { -> delegate.toString().replaceAll(/null/, '0.0').toFloat() }
Integer.metaClass.formatx = { -> delegate.toString().replaceAll(/null/, '0.0').toFloat() }
m2= 4.formatx()
m= "4".formatx()
println null.formatx()
edit
import org.codehaus.groovy.runtime.NullObject
[String, Integer,NullObject].each { it.metaClass.formatx = { -> delegate.toString().replaceAll(/null/, '0.0').toFloat() } }
m2= 4.formatx()
m= "4".formatx()
println null.formatx()

Groovy paradigm for conditional with find

This code works, but the duplicate find seems less than optimal. Is it possible to implement the same functionality without the duplication?
def pattern = ~'some_regex'
def inFile = new File('in')
inFile.eachLine { String line ->
if (line.find(pattern)) {
line.find(pattern) { match ->
... // do something
}
}
else {
... // do something (else)
}
}
I'd suggest to use eachMatch()
inFile.eachLine { String line ->
String matched
line.eachMatch( pattern ){
matched = it[ 0 ]
doSomethingWithMatch matched
}
if( !matched ) doNoMatch()
}

Resources