一个库函数返回 Option<(String, String)>
我做了个函数把它包起来,想给上级返回第二个值的 Option<String>,该怎么写?
新手求助
1
hsfzxjy 2022-06-30 15:29:08 +08:00
x.map(|(a, b)| b)
|
2
timothyye 2022-07-02 13:31:26 +08:00
(String, String) 就是个 tuple 类型
|
3
ecloud OP @hsfzxjy 实际测试了一下这种写法似乎不行,因为(a,b)不是一定存在的,它可能会是 None ,这样写 map 就晕了。似乎除了手写 match 没有啥太好的现成方法
|
4
hsfzxjy 2022-07-06 17:50:25 +08:00 via Android
.map 就是它非 None 时才会执行啊,怎么不对了
|
5
ecloud OP @hsfzxjy 类型不对,写成(a, b)的话,map 会要求输入类型为 tuple ,而万一前面函数返回 None 他就报类型转换错误
|
6
ecloud OP @hsfzxjy 就是说这个该死的函数返回的是 None ,或者(String String),而不是(Option, Option);如果是后者用 map 很舒服的
|
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); 这样是没问题的。或者你能不能给一个行不通的例子? |
8
hsfzxjy 2022-07-06 18:02:32 +08:00 via Android
None 不是类型,是 Option<_>类型的一个值
|
9
ecloud OP @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 |
10
ecloud OP |
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)); |
12
ecloud OP 我感觉编译器认为(_,_)就不是 Option<(String, String)>,这不知道是出于什么考虑还是难道说是一个 bug ?
|
13
hsfzxjy 2022-07-06 18:11:53 +08:00 via Android
要注意看函数返回的类型
|
15
hsfzxjy 2022-07-06 18:14:59 +08:00 via Android
return Ok(con.brpop("ttt", 1)?.map(|(a,b)| b));
也是可以的,你试试 |
16
ecloud OP @hsfzxjy Ok 的写法是不可以的,因为我要返回的是 Option<String>而不是 String ,我还得要处理下 None 的情况。也就是说 None 转 None ,非 None 转 a.1 。而且还要抛错误
|
17
hsfzxjy 2022-07-06 18:21:35 +08:00 via Android
@ecloud 我 15 楼返回的就是 RedisResult<Option<String>>,就是你想要的
|
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)); |
19
ecloud OP @hsfzxjy 都不行的,我感觉 map(a,b)它想要的是(Option, Option)而不收 Option<(T, T)>
|
20
hsfzxjy 2022-07-06 18:39:25 +08:00 via Android
你尝试了吗,不要感觉,不妨试试
map 是可以作用于 Option<(String, String)> |
21
ecloud OP |
22
hsfzxjy 2022-07-06 18:40:49 +08:00 via Android
就是直接把 18 楼的方案替换到你附言的代码中
|
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)) } 写成这样就可以了 |
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>> 就好了 |