< 返回版块

swardsman 发表于 2021-03-21 19:30

Tags:tuple,match

今天碰到了个tuple不能在match语句中正常使用的问题,请问各位大佬这个问题该如何解决?问题再现过程如下:

先用type关键字定义一个新类型(tuple的马甲)

type TestTuple = (i32, i32);

然后实现一个函数,这个函数接收一个i32类型数值作为参数,返回一个Option类型的值。

fn make_some(n : i32) -> Option<i32> {
    Some(n)
}

最后实现test_tuple_in_match函数,这个函数参数为我们上面定义的TestTuple类型和一个i32类型的值,功能是在函数体内使用match语句,测试TestTuple中的第一个值是否与另一个参数值相等

fn test_tuple_in_match(t : TestTuple, v: i32) -> bool {
    let tmp = make_some(v); // 返回Some(v)
    match tmp {
        Some(t.0) => true,  //相等返回true
        None => false, //返回false
        _ => false //不相等返回false
    }
}

最后编写测试代码:

assert_eq!(test_tuple_in_match((1,2),1), true);

编译后报错:

  |
8 |         Some(t.0) => true,
  |               ^
  |               |
  |               expected one of `)`, `,`, `@`, or `|`
  |               help: missing `,`

error[E0023]: this pattern has 2 fields, but the corresponding tuple variant has 1 field

评论区

写评论
munpf 2021-03-23 19:34

可以看这篇:https://kaisery.github.io/trpl-zh-cn/ch06-02-match.html

match里面的Some(x)是从枚举变量中提取值,将Some中的值绑定到x上,不是进行判断,类似let Some(x) = tmp;

w 2021-03-22 09:35

Some(x),只是在tmp为some类型时用x取到tmp里面的值,不能用于判断x是否等于某个外部值,想实现可以用下面的写法,在some语句后跟着判断。

--
👇
swardsman: match内部的Some()是一个求值语句,但是为什么t.0不能在Some()里面求出值呢?

--
👇
c5soft: 还可以这样写:

fn test_tuple_in_match3((t,_):TestTuple, v: i32) -> bool {
    match make_some(v) {
        Some(v) =>  t == v,
        None => false, //返回false
    }
}

不要把rust的match当成c语言的switch来看待,二者没有对等关系,rust的match强大太多

c5soft 2021-03-22 06:43

还可以这样写:

fn test_tuple_in_match(t: TestTuple, v: i32) -> bool {
    let tmp = make_some(v); 
    match tmp {
        Some(v) if v==t.0 => true,
        _ => false, 
    }
}

与C语言的switch/case找齐了

c5soft 2021-03-21 22:11

可以这样理解

--
👇
cyh0: match Option时,Some(x)里的x,相当于函数里的形式参数吧

cyh0 2021-03-21 22:02

match Option时,Some(x)里的x,相当于函数里的形式参数吧

c5soft 2021-03-21 21:48

在match内部的Some(x)是在匹配的时候对x赋值,放t.0就是要把tmp的结果放到t.0中去了,发生了语法错误。再看看下面的代码,可以帮助理解match是如何赋值的:

fn test_tuple_in_match5(t: TestTuple, v: i32) -> bool {
    let tmp = make_some(v); 
    match (tmp,t) {
        (Some(v),(t,_)) => t == v,
        _ => false, 
    }
}

这次发生两次赋值:

let Some(v)=tmp; 
let(t,_)=t;
作者 swardsman 2021-03-21 21:34

match内部的Some()是一个求值语句,但是为什么t.0不能在Some()里面求出值呢?

--
👇
c5soft: 还可以这样写:

fn test_tuple_in_match3((t,_):TestTuple, v: i32) -> bool {
    match make_some(v) {
        Some(v) =>  t == v,
        None => false, //返回false
    }
}

不要把rust的match当成c语言的switch来看待,二者没有对等关系,rust的match强大太多

c5soft 2021-03-21 21:29

match一个Option表达式,只能有Some与None两种结果,不可能再有第三种结果

c5soft 2021-03-21 21:27

看一下这段代码,就能理解match是如何工作的了, match内部Some(a)是一个求值语句,不是c语言的case语句:

fn test_tuple_in_match4(t : TestTuple, v: i32) -> bool {
    let tmp = make_some(v); // 返回Some(v)
    let a = t.0;
    println!("before match a={}",a);
    match tmp {
        Some(a) => {
            println!("Som(a) a={}",a);
            a==t.0
        }
        None => false, 
    }
}

fn main() {
  println!("{}", test_tuple_in_match4((2, 2), 1));
  println!("{}", test_tuple_in_match4((1, 2), 1));
}

c5soft 2021-03-21 21:08

还可以这样写:

fn test_tuple_in_match3((t,_):TestTuple, v: i32) -> bool {
    match make_some(v) {
        Some(v) =>  t == v,
        None => false, //返回false
    }
}

不要把rust的match当成c语言的switch来看待,二者没有对等关系,rust的match强大太多

作者 swardsman 2021-03-21 21:07

重点不是tmp什么类型,重点是为什么Some(node.0)里面的node.0这种形式为什么不行?

--
👇
c5soft: ``` tmp的类型是Option, 不是Option<(i32,i32)>,改成这样就能编译:

fn test_tuple_in_match(t: TestTuple, v: i32) -> bool { let tmp = make_some(v); // 返回Some(v) match tmp { Some(v) => t.0 == v, None => false, //返回false } }

作者 swardsman 2021-03-21 21:05

是的,这样写是可以的,但毕竟不能直接用tuple.0这种形式。我有时间了去提一下。

--
👇
Cupnfish: ```rust fn test_tuple_in_match(t : TestTuple, v: i32) -> bool { let tmp = make_some(v); // 返回Some(v) let a = t.0; match tmp { Some(a) => true, //相等返回true None => false, //返回false _ => false //不相等返回false } }

作者 swardsman 2021-03-21 21:05

是的,这样写是可以的,但毕竟不能直接用tuple.0这种形式。我有时间了去提一下。

--
👇
Cupnfish: ```rust fn test_tuple_in_match(t : TestTuple, v: i32) -> bool { let tmp = make_some(v); // 返回Some(v) let a = t.0; match tmp { Some(a) => true, //相等返回true None => false, //返回false _ => false //不相等返回false } }

c5soft 2021-03-21 20:36

还可以这样写:

fn test_tuple_in_match2(t: TestTuple, v: i32) -> bool {
    make_some(v).map(|x|x==t.0).unwrap_or(false)
}
c5soft 2021-03-21 20:32
tmp的类型是Option<i32>, 不是Option<(i32,i32)>,改成这样就能编译:

fn test_tuple_in_match(t: TestTuple, v: i32) -> bool {
    let tmp = make_some(v); // 返回Some(v)
    match tmp {
        Some(v) =>  t.0 == v,
        None => false, //返回false
    }
}
Cupnfish 2021-03-21 20:28

这里应该是出bug了,毕竟和预期的不同,可以的话去github下rustlang的issue提一下

Cupnfish 2021-03-21 20:26
fn test_tuple_in_match(t : TestTuple, v: i32) -> bool {
    let tmp = make_some(v); // 返回Some(v)
    let a = t.0;
    match tmp {
        Some(a) => true,  //相等返回true
        None => false, //返回false
        _ => false //不相等返回false
    }
}
1 共 17 条评论, 1 页