V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
ecloud
V2EX  ›  Rust

Option<(String, String)>怎么转成 Option<String>

  •  
  •   ecloud · 2022-06-30 15:24:12 +08:00 · 1627 次点击
    这是一个创建于 911 天前的主题,其中的信息可能已经有所发展或是发生改变。

    一个库函数返回 Option<(String, String)>

    我做了个函数把它包起来,想给上级返回第二个值的 Option<String>,该怎么写?

    新手求助

    第 1 条附言  ·  2022-06-30 16:03:43 +08:00
    好吧,自己搞出来了,有点怪
    fn do_redis(con: &mut redis::Connection) -> RedisResult<Option<String>> {
    //con.lpush("ttt", "dsfdsadfds")?;
    let v : Option<(String, String)> = con.brpop("ttt", 1)?;
    match v {
    Some(v) => Ok(Some(v.1)),
    None => Ok(None),
    }
    }
    24 条回复    2022-07-06 19:01:38 +08:00
    hsfzxjy
        1
    hsfzxjy  
       2022-06-30 15:29:08 +08:00
    x.map(|(a, b)| b)
    timothyye
        2
    timothyye  
       2022-07-02 13:31:26 +08:00
    (String, String) 就是个 tuple 类型
    ecloud
        3
    ecloud  
    OP
       2022-07-06 17:43:16 +08:00
    @hsfzxjy 实际测试了一下这种写法似乎不行,因为(a,b)不是一定存在的,它可能会是 None ,这样写 map 就晕了。似乎除了手写 match 没有啥太好的现成方法
    hsfzxjy
        4
    hsfzxjy  
       2022-07-06 17:50:25 +08:00 via Android
    .map 就是它非 None 时才会执行啊,怎么不对了
    ecloud
        5
    ecloud  
    OP
       2022-07-06 17:56:18 +08:00
    @hsfzxjy 类型不对,写成(a, b)的话,map 会要求输入类型为 tuple ,而万一前面函数返回 None 他就报类型转换错误
    ecloud
        6
    ecloud  
    OP
       2022-07-06 17:59:13 +08:00
    @hsfzxjy 就是说这个该死的函数返回的是 None ,或者(String String),而不是(Option, Option);如果是后者用 map 很舒服的
    hsfzxjy
        7
    hsfzxjy  
       2022-07-06 18:00:57 +08:00 via Android
    None 是 Option<_>的一个值啊

    let x : Option<(String,String)>=None;
    x.map(|(a,b)|b);

    这样是没问题的。或者你能不能给一个行不通的例子?
    hsfzxjy
        8
    hsfzxjy  
       2022-07-06 18:02:32 +08:00 via Android
    None 不是类型,是 Option<_>类型的一个值
    ecloud
        9
    ecloud  
    OP
       2022-07-06 18:07:14 +08:00
    @hsfzxjy con.brpop::<&str, Option<(String, String)>>("ttt", 1).map(|a| a.1)报错 error[E0609]: no field `1` on type `Option<(String, String)>`
    con.brpop::<&str, Option<(String, String)>>("ttt", 1).map(|(a, b)| b)报错 error[E0308]: mismatched types
    ecloud
        10
    ecloud  
    OP
       2022-07-06 18:09:11 +08:00
    @hsfzxjy
    = note: expected enum `Option<(String, String)>`
    found tuple `(_, _)`
    hsfzxjy
        11
    hsfzxjy  
       2022-07-06 18:10:32 +08:00 via Android
    因为 brpop 返回的是 RedisResult<Option<(String, String)>>,你要这样
    return Ok(con.brpop("ttt", 1)?.map(|a| a.1));
    ecloud
        12
    ecloud  
    OP
       2022-07-06 18:10:45 +08:00
    我感觉编译器认为(_,_)就不是 Option<(String, String)>,这不知道是出于什么考虑还是难道说是一个 bug ?
    hsfzxjy
        13
    hsfzxjy  
       2022-07-06 18:11:53 +08:00 via Android
    要注意看函数返回的类型
    ecloud
        14
    ecloud  
    OP
       2022-07-06 18:13:12 +08:00
    @hsfzxjy a.1 这种写法是有可能的,但是(a,b)这种写法看起来怎么都弄不过去
    hsfzxjy
        15
    hsfzxjy  
       2022-07-06 18:14:59 +08:00 via Android
    return Ok(con.brpop("ttt", 1)?.map(|(a,b)| b));

    也是可以的,你试试
    ecloud
        16
    ecloud  
    OP
       2022-07-06 18:18:03 +08:00
    @hsfzxjy Ok 的写法是不可以的,因为我要返回的是 Option<String>而不是 String ,我还得要处理下 None 的情况。也就是说 None 转 None ,非 None 转 a.1 。而且还要抛错误
    hsfzxjy
        17
    hsfzxjy  
       2022-07-06 18:21:35 +08:00 via Android
    @ecloud 我 15 楼返回的就是 RedisResult<Option<String>>,就是你想要的
    hsfzxjy
        18
    hsfzxjy  
       2022-07-06 18:22:54 +08:00 via Android
    可能需要加类型指引

    return Ok(con.brpop::<&str, Option<(String, String)>>("ttt", 1)?.map(|(a,b)| b));
    ecloud
        19
    ecloud  
    OP
       2022-07-06 18:36:45 +08:00
    @hsfzxjy 都不行的,我感觉 map(a,b)它想要的是(Option, Option)而不收 Option<(T, T)>
    hsfzxjy
        20
    hsfzxjy  
       2022-07-06 18:39:25 +08:00 via Android
    你尝试了吗,不要感觉,不妨试试

    map 是可以作用于 Option<(String, String)>
    ecloud
        21
    ecloud  
    OP
       2022-07-06 18:40:21 +08:00
    @hsfzxjy
    = note: expected enum `Option<(String, String)>`
    found tuple `(_, _)`
    hsfzxjy
        22
    hsfzxjy  
       2022-07-06 18:40:49 +08:00 via Android
    就是直接把 18 楼的方案替换到你附言的代码中
    hsfzxjy
        23
    hsfzxjy  
       2022-07-06 18:52:49 +08:00
    fn do_redis(con: &mut redis::Connection) -> RedisResult<Option<String>> {
    Ok(con
    .brpop::<_, Option<(String, String)>>("ttt", 1)?
    .map(|(a, b)| b))
    }

    写成这样就可以了
    hsfzxjy
        24
    hsfzxjy  
       2022-07-06 19:01:38 +08:00   ❤️ 1
    我来给你分析一下

    首先 con.brpop::<_, Option<(String, String)>>("ttt", 1) 返回的是 RedisResult<Option<(String, String)>>,他有几个可能值

    1. Err(_) 发生了错误
    2. Ok(None) 正常返回了,但是内容为空
    3. Ok((str1, str2)) 正常返回了非空内容

    接下来的 ? 操作符会把 RedisResult<Option<(String, String)>> 变为 Option<(String, String)。如果是第一种情况,则这里会提前把错误抛出去,否则,提取出来的 Option<(String, String)> 会继续下面的变换

    然后你要知道,对于一个类型为 Option<U> 的值 x ,以及一个变换函数 f: Fn(U) -> T ,x.map(f) 会变成一个 Option<T> 类型的值。

    带入到你的场景就是 U = (String, String), T = String, 变换函数 |(a,b)| b 的类型是 Fn((String,String) -> String 。

    所以 .map(|(a,b)|b) 会接着把 Option<(String, String)> 变成 Option<String>。

    最后,你的函数想要一个 RedisResult<Option<String>> 的返回值,那只需使用 Ok() 把 Option<String> 变成 RedisResult<Option<String>> 就好了
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2363 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 40ms · UTC 16:00 · PVG 00:00 · LAX 08:00 · JFK 11:00
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.