How to access rust variables outside the scope? - 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!)

Related

How to use if let statement with conditions?

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
}

Is it a cleaner way to write the following code in rust?

for x in strategies {
let mut flag = true;
for y in x {
if y {
flag = false;
break;
}
}
if flag {
// do something
}
}
I really hate the use of the flag, and it adds unnecessary branch instructions. I am thinking if there is a way that we can execute // do something if the inner loop exit normally and don't do it if it breaks.
In place of the inner loop, you can take the negation of Iterator::any applied over an identity method such as |y| y or std::convert::identity:
for x in strategies {
// if it's not the case that any are true
if !x.into_iter().any(|y| y) {
// do something
}
}
Equivalently, you can take Iterator::all applied over a negating method such as |y| !y or <bool as std::ops::Not>::not:
use std::ops::Not;
for x in strategies {
// if it is the case that all are false
if x.into_iter().all(Not::not) {
// do something
}
}
Either way, if x is already an Iterator, then the call to .into_iter() is superfluous and can be omitted.

Recreating the if/else in groovy: giving multiple closures arguments to a function

While trying to reinvent the if/else syntax with closures in groovy, I couldn't manage to make it work. I think putting multiple closures outside the parenthesis is not permitted, but it could be something else.
If it isn't permitted, how would you reproduce the if/else syntax? This is a thought experiment, so don't tell me about the the inefficiency of this implementation.
My code:
void ifx(boolean condition, Closure action){
["${true.toString()}": action].get(condition.toString(), {})()
}
void ifx(boolean condition, Closure action, Closure elsex){
["${true.toString()}": action, "${false.toString()}": elsex].get(condition.toString())()
}
void elsex(Closure action){
action()
}
ifx(1==2){
println("1")
} ifx(1==3){
println("2")
} elsex{
println("3")
}
Error message:
java.lang.NullPointerException: Cannot invoke method ifx() on null
object
Something along these lines works:
updated with closures to avoid global state:
def ifx( outerCondition, outerBlock ) {
boolean matched = false
def realIfx
realIfx = { condition, block ->
if (condition) {
matched = true
block()
}
[ifx: realIfx, elsex: { elseBlock -> if(!matched) elseBlock() }]
}
realIfx outerCondition, outerBlock
}
And some testing:
def result
ifx(1 == 2) {
result = 1
} ifx(1 == 3) {
result = 2
} elsex {
result = 3
}
assert result == 3
result = null
ifx (1 == 2) {
result = 1
} ifx (2 == 2) {
result = 2
} elsex {
result = 3
}
assert result == 2
result = null
ifx (true) {
result = 1
} ifx (2 == 1) {
result = 2
} elsex {
result = 3
}
assert result == 1
ifx (1==2) {} ifx(1==3) {} elsex {} is a command chain expression translating to ifx(1==2,{}).ifx(1==3,{}).elsex({}). Since void translates to null, it should be clear that the second ifx call then fails with a NPE. To realize an if/else kind of thing I would maybe do the following
void ifx(boolean condition, Closure ifBlock, Closure elseBlock) {
....
}
ifx (1==2) {...}{...}
meaning not using an else keyword at all. IF you want to keep your idea, you have to return something on which you can call elsex and ifx.. Or if not ifx, then put a newline in after the first ifx

How do a pass a database variable to a function in Rust?

I'm just starting to look at Rust. I wanted to experiment with a database, and found the sqlite repo which is good to have to experiment with.
I would like to know the "correct" way to pass the sqlite database variable to a function. The error messages that I was initially getting from the compiler appeared to indicate that when I passed the Db variable from main() to the function, it was gone, so I returned it. Although this appears to work, it doesn't seem to me that it would be the normal way. While I'm not a believer in a large number of Global variables, I attempted to create a Global variables, but I couldn't discover how to do that.
Below is the test program. Please note that I am not yet using the Rust naming conventions, but it is very-early days
The main lines in question are :
oDb1 = fCreateTable(oDb1);
fn fCreateTable(oDb1:sqlite::database::Database) -> sqlite::database::Database {
and what is the alternative and why is it necessary (in this instance) to return it?
Example program:
extern mod sqlite;
fn main() {
let mut oDb1:sqlite::database::Database;
oDb1 = fOpenDb();
oDb1 = fCreateTable(oDb1) ;
let mut iInsertTot: int = 0;
while iInsertTot < 25 {
let oDbExec = oDb1.exec("INSERT INTO test (sname, iborn) VALUES ('xxxxx', 1973)");
if (! oDbExec.is_ok()) {
fail!(fmt!("Insert Nr. %d Failed!", iInsertTot+1));
}
iInsertTot += 1;
}
println (fmt!("Inserts completed = %d", iInsertTot));
}
fn fOpenDb() -> sqlite::database::Database {
let oDbOpen = sqlite::open("test.db");
if oDbOpen.is_err() {
fail!(fmt!("Error opening test.db: %?", oDbOpen));
}
println(fmt!("Database Open OK? %?", oDbOpen.is_ok()));
oDbOpen.unwrap()
}
fn fCreateTable(oDb1:sqlite::database::Database) -> sqlite::database::Database {
let mut oDbExec = oDb1.exec("drop table if exists test");
println(fmt!("Drop Table OK? %?", oDbExec.is_ok()));
if (!oDbExec.is_ok()) {
fail!("Drop-table failed");
}
oDbExec = oDb1.exec("CREATE TABLE test (ikey INTEGER PRIMARY KEY not null,
sname text, iborn int)");
println(fmt!("Create OK? %?", oDbExec.is_ok()));
if !oDbExec.is_ok() {
fail!("Create Table failed");
}
oDb1
}
sqlite::database::Database implements Drop, meaning it has a destructor, meaning it is never copied and always moved: fCreateTable(oDb1) moves the database object out of oDb1: Now there's nothing left in oDb1! Of course, you can put back something. For example, when you return the database from fCreateTable, you again move - back into fCreateTable.
But this is a silly dance. Just don't move the database in the first place, borrowed a pointer to it:
fn main() {
let oDb1 = fOpenDb();
fCreateTable(&oDb1);
...
}
fn fCreateTable(oDb1: &sqlite::database::Database) {
...
}

how can I create a reference to a variable in specman?

I have the following code in specman:
var x := some.very.long.path.to.a.variable.in.another.struct;
while (x == some_value) {
//do something that uses x;
//wait for something
//get a new value for x
x = some.very.long.path.to.a.variable.in.another.struct;
};
Now, it seems wasteful to write the assignment to x twice; once during initialization and once during the loop.
What I really want to use is a reference to the long variable name, so that I could do:
var x := reference to some.very.long.path.to.a.variable.in.another.struct;
while (x == some_value) {
//do something that uses x;
//wait for something
//no need to update x now since it's a reference
};
Can this be done in specman?
specman/e generally uses references for structs and lists, so if your variable type is either of it your second example should work. For integer or boolean I don't know a way to use a reference for a variable. Anyway, two ideas which might help you:
Add a pointer to the other struct and bind it in a config file:
struct a { other_variable : uint; };
struct b {
other_struct : a;
some_func() is {
var x : uint = other_struct.other_variable;
while (x == some_value) {
x = other_struct.other_variable;
};
};
};
extend cfg {
struct_a : a;
struct_b : b;
keep struct_b.other_struct == struct_a;
};
UPDATE: You can find some more information on this technique in this Team Specman Post.
Wrap your while loop in a function, there you can pass parameters by reference (see help pass reference):
some_func(x : *uint) is {
while (x == some_value) {
// stuff ...
};
};
Hope this helps!
Daniel

Resources