Patterns

#rust #pattern-mach

nested or-patterns #

https://blog.rust-lang.org/inside-rust/2020/03/04/recent-future-pattern-matching-improvements.html

Essentially, | isn’t a special syntax for match statements but actually a kind of operator used in all pattern matching contexts

// instead of this
match value {
    Some(2) | Some(3) | Some(5) | Some(7) => println!("prime"),
    Some(0) | Some(1) | Some(4) | Some(9) => println!("square"),
    None => println!("nothing"),
    _ => println!("something else"),
}

// try this, 可以直接在 constructor 内部解构
match value {
    Some(2 | 3 | 5 | 7) => println!("prime"),
    Some(0 | 1 | 4 | 9) => println!("square"),
    None => println!("nothing"),
    _ => println!("something else"),
}

// 同样应用于 if-let
if let Some("fn" | "let" | "if") = token {
    println!("keyword");
}

// 多个值,不是 tuple
match vec {
    (0, 0) => println!("here"),
    (-1 | 0 | 1, -1 | 0 | 1) => println!("close"),
    _ => println!("far away"),
}
// guard 例子
// guard 是 match 有,if-let 等没有的
match opt {
    Some(x) if x % 2 == 0 => "even",
    Some(_odd) => "odd",
    None => "nothing",
}

// matches!(expr, pattern) -> bool
#[test]  
fn test_matches_macro() {  
	assert!(matches!("23".parse::<u8>(), Ok(_)));  
	assert!(!matches!("23".parse::<u8>(), Ok(24)));  
	assert!(matches!("a23".parse::<u8>(), Err(_)));  
}

// binding
match value {
    Some(p @ 2 | 3 | 5 | 7) => println!("{p} is a prime"),
    Some(sq @ 0 | 1 | 4 | 9) => println!("{sq} is a square"),
    None => println!("nothing"),
    Some(n) => println!("{n} is something else"),
}

// 
let (Ok(i) | Err(i)) = [1, 2, 3].binary_search(&2);
// binary_search

// 这个语法上是可以的,但是没什么用
// 只能是 Result<i32, i32>, 两个类型必须相同
// elixir 在这个事情上做得更好
fn f((Ok(i) | Err(i)): Result<i32, i32>) {}


let some_value = 3;
if let 1 | 2 | 3 = some_value {
    println!("asfasdf");
}

// 
enum Num {
	variant1(u32),
	variant2(u32),
}

match num {
	variant1(inner) | variant2(inner) => {
		println!("{inner}");
	}
}

// 
enum MusicInfo {
    Artist { name: String },
    Album { title: String },
}

fn main() {
    let artist = MusicInfo::Artist { name: "Keith Jarrett".into() };
    let album = MusicInfo::Album { title: "The Köln Concert".into() };
    let music_info = if rand::random() { artist } else { album };
    let (MusicInfo::Artist { name } | MusicInfo::Album { title: name }) = music_info;
    println!("{name}")
}