< 返回版块

Neutron3529 发表于 2020-11-15 01:12

if let是一个很强大的语法糖,如果能正确使用应该会省许多功夫,毕竟改C#游戏的时候满眼类似if (xxx!=NULL && xxx.yyy!=NULL && xxx.yyy>zzz)这样的条件真的令人头疼

但问题是,应该如何正确使用这个函数?

比如,如果我们想实现while (vec.last().is_some()) && (vec.last().unwrap()>0),比如

let mut counter=10;
let mut vec=vec![1,2,3,4,5];

while (counter>0) && (vec.last().is_some()) && (vec.last().unwrap()>0){
  //do something
  counter-1
}

理论上我们可以把vec.last().is_some()省略直接写

match vec.last(){
  Some(x) if x>0=>{},
  _=>()
}

这跟if-let语句很相似——但我并不知道如何用if-let改写类似的语句

而,由于这里的逻辑是while,写成if和if-let的嵌套会很麻烦(所有逻辑的else一定要写上break)

想问一下大家有没有改写嵌套while-let的经验,或者说这种东西怎么改写更优雅。

目前我能想到的改写方法是loop{match}然后在match里面写上_=>break

//今天的leetcode
            loop{
                match numStack.last().copied(){
                    Some(d) if k>0 && d>digit=>{
                        numStack.pop();
                        k -= 1;
                    }
                    _=>break
                }
            }

不知道有没有更优雅的写法,但至少写成下面这样是会报错的:

//错误代码
            while let (Some(d) if k>0 && d>digit)=numStack.last().copied(){
                        numStack.pop();
                        k -= 1;
            }
Line 7, Char 32: expected identifier, found keyword `if` (solution.rs)
  |
7 |             while let (Some(d) if k>0 && d>digit)=numStack.last().copied(){
  |                                ^^ expected identifier, found keyword
Line 7, Char 32: expected one of `)`, `,`, or `|`, found keyword `if` (solution.rs)
  |
7 |             while let (Some(d) if k>0 && d>digit)=numStack.last().copied(){
  |                               -^^ expected one of `)`, `,`, or `|`
  |                               |
  |                               help: missing `,`
Line 7, Char 35: expected one of `)`, `,`, `@`, or `|`, found `k` (solution.rs)
  |
7 |             while let (Some(d) if k>0 && d>digit)=numStack.last().copied(){
  |                                  -^ expected one of `)`, `,`, `@`, or `|`
  |                                  |
  |                                  help: missing `,`
Line 7, Char 36: expected one of `)`, `,`, `@`, or `|`, found `>` (solution.rs)
  |
7 |             while let (Some(d) if k>0 && d>digit)=numStack.last().copied(){
  |                                    ^ expected one of `)`, `,`, `@`, or `|`
error: aborting due to 4 previous errors

评论区

写评论
spacemeowx2 2020-11-23 19:07

不知道用.map会不会符合题主的意思

    while let Some(true) = vec.last().map(|v| (counter>0) && (v>&0)) {
      //do something
      counter-=1;
    }
作者 Neutron3529 2020-11-16 20:33

我并不是想强行一行解决

只是想找到一个额外开销最小的写法。

之前试过,比如比较大小的时候,用and_then()写比较大小的条件,慢于把两个i32拼成一个i64

所以对Rust里面的各种繁琐结构还是有些害怕的。


👇
AbdyCjen: while (vec.last().is_some()) && (vec.last().unwrap()>0)

这个应该可以替换成等效的while let

while let Some(0..=i32::MAX) = vec.last()

但是这个:

while let (Some(d) if k>0 && d>digit)=numStack.last().copied()

没有办法用:

while let (Some(d @ digit..=i32::MAX), 1..i32::MAX) = (numStack.last().copied(), k)

因为RangePatternBound如果用变量会报错;

如果强行一行流可以试试:

while let Some(d) = vec.last().copied().filter(|c| c > &digit && count > 0)

参考链接:

rust_reference

rfc2497

作者 Neutron3529 2020-11-16 20:29

因为我不知道啊……

以及,如果之后需要利用vec.last().unwrap()的值的话,这里写matches!的话,后面还需要来一个let x=vec.last().unwrap()之类的操作

不过好像这里的话,用matches!正合适

谢谢了:)

--
👇
93996817: 为啥不用 matches! 呢?

  let    counter=10;
  let    vec=vec![1,2,3,4,5];
  if (counter>0) && (vec.last().is_some()) && (*vec.last().unwrap()>0){
     println!("true!");
  }

  if(counter>0) && matches!(vec.last(),Some(&x) if x>0){
    println!("true!");
  }

93996817 2020-11-16 10:00

为啥不用 matches! 呢?

  let    counter=10;
  let    vec=vec![1,2,3,4,5];
  if (counter>0) && (vec.last().is_some()) && (*vec.last().unwrap()>0){
     println!("true!");
  }

  if(counter>0) && matches!(vec.last(),Some(&x) if x>0){
    println!("true!");
  }

AbdyCjen 2020-11-15 02:40
while (vec.last().is_some()) && (vec.last().unwrap()>0)

这个应该可以替换成等效的while let

while let Some(0..=i32::MAX) = vec.last()

但是这个:

while let (Some(d) if k>0 && d>digit)=numStack.last().copied()

没有办法用:

while let (Some(d @ digit..=i32::MAX), 1..i32::MAX) = (numStack.last().copied(), k)

因为RangePatternBound如果用变量会报错;

如果强行一行流可以试试:

while let Some(d) = vec.last().copied().filter(|c| c > &digit && count > 0)

参考链接:

rust_reference

rfc2497

1 共 5 条评论, 1 页