ecloud
V2EX  ›  Rust

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

By ecloud at 2022 年 6 月 30 日 · 2646 次点击

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

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

新手求助

第 1 条附言  ·  2022 年 6 月 30 日
好吧,自己搞出来了,有点怪
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 年 6 月 30 日
x.map(|(a, b)| b)
timothyye
   2
timothyye  
   2022 年 7 月 2 日
(String, String) 就是个 tuple 类型
ecloud
   3
ecloud  
OP
   2022 年 7 月 6 日
@hsfzxjy 实际测试了一下这种写法似乎不行,因为(a,b)不是一定存在的,它可能会是 None ,这样写 map 就晕了。似乎除了手写 match 没有啥太好的现成方法
hsfzxjy
   4
hsfzxjy  
   2022 年 7 月 6 日 via Android
.map 就是它非 None 时才会执行啊,怎么不对了
ecloud
   5
ecloud  
OP
   2022 年 7 月 6 日
@hsfzxjy 类型不对,写成(a, b)的话,map 会要求输入类型为 tuple ,而万一前面函数返回 None 他就报类型转换错误
ecloud
   6
ecloud  
OP
   2022 年 7 月 6 日
@hsfzxjy 就是说这个该死的函数返回的是 None ,或者(String String),而不是(Option, Option);如果是后者用 map 很舒服的
hsfzxjy
   7
hsfzxjy  
   2022 年 7 月 6 日 via Android
None 是 Option<_>的一个值啊

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

这样是没问题的。或者你能不能给一个行不通的例子?
hsfzxjy
   8
hsfzxjy  
   2022 年 7 月 6 日 via Android
None 不是类型,是 Option<_>类型的一个值
ecloud
   9
ecloud  
OP
   2022 年 7 月 6 日
@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 年 7 月 6 日
@hsfzxjy
= note: expected enum `Option<(String, String)>`
found tuple `(_, _)`
hsfzxjy
   11
hsfzxjy  
   2022 年 7 月 6 日 via Android
因为 brpop 返回的是 RedisResult<Option<(String, String)>>,你要这样
return Ok(con.brpop("ttt", 1)?.map(|a| a.1));
ecloud
   12
ecloud  
OP
   2022 年 7 月 6 日
我感觉编译器认为(_,_)就不是 Option<(String, String)>,这不知道是出于什么考虑还是难道说是一个 bug ?
hsfzxjy
   13
hsfzxjy  
   2022 年 7 月 6 日 via Android
要注意看函数返回的类型
ecloud
   14
ecloud  
OP
   2022 年 7 月 6 日
@hsfzxjy a.1 这种写法是有可能的,但是(a,b)这种写法看起来怎么都弄不过去
hsfzxjy
   15
hsfzxjy  
   2022 年 7 月 6 日 via Android
return Ok(con.brpop("ttt", 1)?.map(|(a,b)| b));

也是可以的,你试试
ecloud
   16
ecloud  
OP
   2022 年 7 月 6 日
@hsfzxjy Ok 的写法是不可以的,因为我要返回的是 Option<String>而不是 String ,我还得要处理下 None 的情况。也就是说 None 转 None ,非 None 转 a.1 。而且还要抛错误
hsfzxjy
   17
hsfzxjy  
   2022 年 7 月 6 日 via Android
@ecloud 我 15 楼返回的就是 RedisResult<Option<String>>,就是你想要的
hsfzxjy
   18
hsfzxjy  
   2022 年 7 月 6 日 via Android
可能需要加类型指引

return Ok(con.brpop::<&str, Option<(String, String)>>("ttt", 1)?.map(|(a,b)| b));
ecloud
   19
ecloud  
OP
   2022 年 7 月 6 日
@hsfzxjy 都不行的,我感觉 map(a,b)它想要的是(Option, Option)而不收 Option<(T, T)>
hsfzxjy
   20
hsfzxjy  
   2022 年 7 月 6 日 via Android
你尝试了吗,不要感觉,不妨试试

map 是可以作用于 Option<(String, String)>
ecloud
   21
ecloud  
OP
   2022 年 7 月 6 日
@hsfzxjy
= note: expected enum `Option<(String, String)>`
found tuple `(_, _)`
hsfzxjy
   22
hsfzxjy  
   2022 年 7 月 6 日 via Android
就是直接把 18 楼的方案替换到你附言的代码中
hsfzxjy
   23
hsfzxjy  
   2022 年 7 月 6 日
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 年 7 月 6 日   ❤️ 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>> 就好了
© 2026 V2EX · 27ms · 3.9.8.5