i want to know the key difference between if
and match
what is the thing that i can do in if
or match
and i cannot do in the other one ?
The main difference is that an if
just lets you change the control flow depending on a boolean condition, while a match
statement does pattern matching.
That means you can change the control flow based on the state of a particular field or an enum variant, bind things to variables, or arbitrary logic using an if
guard.
struct Person {
name: String,
address: Option<Address>,
}
struct Address {
street: String,
building: BuildingType,
country: String,
}
impl std::fmt::Display for Address { ... }
enum BuildingType {
Normal,
Apartment(u32),
Lot(u32),
}
match some_person {
Person {
name,
address:
Some(
ref address @ Address {
building: BuildingType::Apartment(a),
..
},
),
} if a % 2 == 0 => {
println!("{name} lives in an even-numbered apartment, {address}");
}
Person {
name,
address: Some(address),
} => println!("{name} lives at {address}"),
Person {
name,
address: None,
} => println!("{name} has no known address"),
}
It's possible to implement if
using match
, but not the other way around.
match condition {
true => { ... },
false => { ... },
}
You also have an if-let statement, which is essentially a match
statement where we only check one arm and don't support if-guards.
i don't understand what do you mean by if and boolean ? i can use boolean in both if and match i still don't get it
An if
expressions' discriminant can only be a Boolean. In a match
, you can use any pattern.
that is not a difference because i can add more pattern matching in match
adding more else if
in if statement
does not make a difference
how boolean i don't understand ?
if
doesn't let you pattern match and extract the value inside the pattern at the same time. You can do that with if let
though, but you won't be able to exhaustively match multiple patterns i.e. the compiler won't check that you covered all cases, and even if you do it will conservately assume you didn't.
A Boolean is the logical type for true
and false
. If you don't know what a Boolean is, then I'm sorry, I can't help you, you'll need to study some basics first.
i know what booleans are i can also mention the type using bool
in rust you didn't understand my question,
i mean what you mean by booleans what are you referring to ? if
returns anything as match
and if x == true
this is a simple boolean matching in if statement but what do you mean ? be specific with examples. i hope you understand me i am not talking about booleans themselves i know what they are
if <<SOMETHING_HERE>> {...}
<<SOMETHING_HERE>>
-> so called "discriminant", can be only something that is either boolean or "resolves" to boolean (fn returning bool, etc.)
The thing that you can make checks to other things booeans by adding e.g . == something_else
is transitioning root question of statement definition/difference out of original scope a bit...
Of course you can add more else if
s further, but it always has to be "something boolean-ish" (i am not familiar with proper terminology so please excuse my pseudo definitions), and they are logically speaking completely new/different/subsequent if statements, not bound to first if
in any way...
On the other hand, match
accepts other types (event "mixes of types via tuples etc).
This (among other things) from my point of view allows for shortening otherwise cumbersome lengthy chains of if-else statements into neat & concise blocks.
let greeting = "ahoy";
let value = 42;
// matching on "combination" of str/num in single statement,
// without need to compose complex if else &&/||
// conditions several times on different rows
match (greeting, value) {
("ahoy", 42) => println!("Ahoy life!"),
("ahoy", num) => println!("Bye {num} - i print only 42!"),
_ => println!("'Sup..."),
}
Edit, if i really really had to "define" match on single short sentence, i'd say it's simplified "ugly mess of if/else statements" on steroids.
Sorry, this is completely incomprehensible. If you are having trouble expressing yourself in English reasonably well, then please seek the help of someone who can translate your question to English.
i don't have any problems with english at all you just misunderstood my questions maybe they are too complicated for you to understand but i appreciate your comments
A question about if
and match
is definitely not too complicated for me. I've been using Rust for 6 years and I've been writing code since I was nine. Your question I quoted above is not coherent, I'm sorry but that's not my fault.
Several people have been trying to explain various aspects of what you could possibly be asking, and you were satisfied with none of the answers. Maybe the problem is not with everyone else.
thanks for your comments
There are things that are difficult to do without match
(mainly because of lifetimes), but there is nothing that really can't be done without match
. Hypothetical Rust without match
would still be Turing-complete and thus technically capable of doing anything Rust with match
can, if you tried hard enough.
That said, using match
provides enormous safety and usability benefits that are very much worth learning.
At the surface, match
looks similar to switch
statement in other languages. However match
is much better in many ways. I'll explain some of that below.
Look at this code which uses if
but not match
:
// Let's suppose you have some Option<T> and you want a value of T
if opt.is_some() {
let val = opt.unwrap();
// use val
}
See the is_some
and unwrap
methods that do essentially the same thing? It's redundant and it wastes everyone's cognitive efforts. With match
we can do better:
match opt {
Some(val) => {
// use val
},
None => {}
}
// Or with `if let`:
if let Some(val) = opt {
// use val
}
We're no longer repeating ourselves! Instead, we've managed to extract val
with the same syntax we've used to check the option's state. While this particular problem could as well have been solved with and_then
, match
is still great as it scales much better to more complex scenarios.
match
is also intelligent. While if
blindly obeys whatever the comparison operator of your choice says, match
's built-in patterns have more knowledge over the types you're matching.
Let's see it in action:
let mut array = [SomeValue, OtherValue];
take_two_muts(&mut array[0], &mut array[1]);
This code cannot compile because indexing into an array causes the entire array to be borrowed. Without patterns, we would have to resort to unsafe
code here. Again, we can do better:
let [mut first, mut second] = array;
take_two_muts(&mut first, &mut second);
Note that first
and second
are now each their own variables with no relation to each other. This causes the version with pattern usage to compile successfully.
The Reference page on Patterns catalogs the variety of types that are natively understood by the language, as well as other things you can do using patterns.
To give an example:
// NOTE: `MyType` does not implement `PartialEq`
enum MyType {
A,
B,
}
fn foo() -> &'static str {
let x = MyType::A;
// You cannot do:
/*
if x == MyType::A {
println!("Got A");
} else if x == MyType::B {
println!("Got B");
}
*/
// We must do:
if let MyType::A = x {
"Got A"
} else if let MyType::B = x {
"Got B"
} else {
// We cannot omit this, but if we used `match` we could.
unreachable!("should never happen")
}
}
fn bar() -> &'static str {
let x = MyType::A;
match x {
MyType::A => "Got A",
MyType::B => "Got B",
}
}
Another (sometimes important) difference is drop order:
#![allow(dead_code)]
enum MyType {
A,
B,
}
impl Drop for MyType {
fn drop(&mut self) {
println!("Dropped");
}
}
impl MyType {
fn is_a(&self) -> bool {
match &self {
MyType::A => true,
MyType::B => false,
}
}
}
fn get_a() -> MyType {
MyType::A
}
fn foo() {
if get_a().is_a() {
println!("foo")
}
}
fn bar() {
match get_a().is_a() {
true => println!("bar"),
false => (),
}
}
fn main() {
println!("Calling foo():");
foo();
println!("");
println!("Calling bar():");
bar();
}
Output:
Calling foo():
Dropped
foo
Calling bar():
bar
Dropped
You can see that in case of foo()
, which uses if
, the value returned by get_a()
is dropped before println!("foo")
gets executed. If you write the exact same with match
, then the value will be dropped after println!("bar")
has been executed.
This is also explicitly noted in the Rust reference in the section on temporary scopes:
The scrutinee of a
match
expression is not a temporary scope, so temporaries in the scrutinee can be dropped after thematch
expression. For example, the temporary for1
inmatch 1 { ref mut z => z };
lives until the end of the statement.
This can matter in practice, for example, if you use Mutex::lock
or RefCell::borrow
within the boolean expression of if
or in the match
scrutinee.