-
Notifications
You must be signed in to change notification settings - Fork 1.1k
result-panic/result #241
-
result-panic/result
Learning Rust By Practice, narrowing the gap between beginner and skilled-dev with challenging examples, exercises and projects.
Beta Was this translation helpful? Give feedback.
All reactions
-
👍 6 -
🎉 3 -
👀 2
Replies: 24 comments 12 replies
-
第一题的题目和答案对不上
Beta Was this translation helpful? Give feedback.
All reactions
-
感觉是我理解错了,我以为只能填写横线,不能改动其它地方
Beta Was this translation helpful? Give feedback.
All reactions
-
有大佬解惑吗?这里为什么不能用两个map,前面必须用and_then会报错。
// 提示:使用 and_then
和 map
fn multiply1(n1_str: &str, n2_str: &str) -> Result<i32, ParseIntError> {
n1_str.parse::().map(|x|n2_str.parse::().map(|y|{x*y}))
}
Beta Was this translation helpful? Give feedback.
All reactions
-
原因是map使用的闭包函数的返回类型不是Result,第二个map不适合放到第一个map的闭包函数里。
pub fn and_then<U, F>(self, op: F) -> Result<U, E>
where
F: FnOnce(T) -> Result<U, E>,
pub fn map<U, F>(self, op: F) -> Result<U, E>
where
F: FnOnce(T) -> U,
Beta Was this translation helpful? Give feedback.
All reactions
-
fn multiply(n1_str: &str, n2_str: &str) -> Result<i32, ParseIntError> {
let n1 = n1_str.parse::<i32>();
let n2 = n2_str.parse::<i32>();
n1.and_then(|x| n2.map(|y| y * x))
}
Beta Was this translation helpful? Give feedback.
All reactions
-
本题中函数multiply返回的类型是Result<i32, ParseIntError>,
如果用两个map那么返回值就变成了Result< Result<i32, ParseIntError>, ParseIntError>了.
嵌套的map 会返回一个 Result<i32, ParseIntError>, 此时会变成外层的map返回的Result的Ok值
Beta Was this translation helpful? Give feedback.
All reactions
-
👍 4
-
pub fn map<U, F: FnOnce(T) -> U>(self, op: F) -> Result<U, E> {
match self {
Ok(t) => Ok(op(t)),
Err(e) => Err(e),
}
}
pub fn and_then<U, F: FnOnce(T) -> Result<U, E>>(self, op: F) -> Result<U, E> {
match self {
Ok(t) => op(t),
Err(e) => Err(e),
}
}
Beta Was this translation helpful? Give feedback.
All reactions
-
因为map要求的闭包必须返回的是一个T类型,在这里是返回i32类型,但map本身又是返回的Result类型;所以两个map嵌套用的话,内嵌的map的返回类型没法满足外层map对所需闭包的要求。
Beta Was this translation helpful? Give feedback.
All reactions
-
5题另一种实现:
Ok(n1_str.parse::<i32>()? * n2_str.parse::<i32>()?)
Beta Was this translation helpful? Give feedback.
All reactions
-
第5题:我是这么写的,这块东西还没讲到
type Res = Result<T, ParseIntError>;
Beta Was this translation helpful? Give feedback.
All reactions
-
main里的return问题
原题如果改成用特征对象就会报错
use std::num::ParseIntError; fn main() -> Result<(), Box<dyn std::error::Error>> { let number_str = "10"; let number = match number_str.parse::<i32>() { Ok(number) => number, Err(e) => return Err(e), }; println!("{}", number); Ok(()) }
用?
就成功,这是为什么呢?不是说?
是个宏,其实也是return了Err(e)的吗?
use std::num::ParseIntError; fn main() -> Result<(), Box<dyn std::error::Error>> { let number_str = "10"; let number = number_str.parse::<i32>()?; println!("{}", number); Ok(()) }
Beta Was this translation helpful? Give feedback.
All reactions
-
Ok 犯蠢了
Err(e) => return Err(Box::new(e)),
就可以了
Beta Was this translation helpful? Give feedback.
All reactions
-
mark
Beta Was this translation helpful? Give feedback.
All reactions
-
第一题:
// 填空并修复错误 use std::num::ParseIntError; fn multiply(n1_str: &str, n2_str: &str) -> Result<i32, ParseIntError> { let n1 = n1_str.parse::<i32>(); let n2 = n2_str.parse::<i32>(); Ok(n1.unwrap() * n2.unwrap()) } fn main() { let result = multiply("10", "2"); assert_eq!(result, Ok(20)); let result = multiply("4", "2"); assert_eq!(result.unwrap(), 8); println!("Success!") }
第二题:
use std::num::ParseIntError; // 使用 `?` 来实现 multiply // 不要使用 unwrap ! fn multiply(n1_str: &str, n2_str: &str) -> Result<i32, ParseIntError> { Ok(n1_str.parse::<i32>()? * n2_str.parse::<i32>()?) } fn main() { assert_eq!(multiply("3", "4").unwrap(), 12); println!("Success!") }
第三题:
use std::fs::File; use std::io::{self, Read}; fn read_file1() -> Result<String, io::Error> { let f = File::open("hello.txt"); let mut f = match f { Ok(file) => file, Err(e) => return Err(e), }; let mut s = String::new(); match f.read_to_string(&mut s) { Ok(_) => Ok(s), Err(e) => Err(e), } } // 填空 // 不要修改其它代码 fn read_file2() -> Result<String, io::Error> { let mut s = String::new(); File::open("hello.txt")?.read_to_string(&mut s)?; Ok(s) } fn main() { assert_eq!(read_file1().unwrap_err().to_string(), read_file2().unwrap_err().to_string()); println!("Success!") }
第四题:
use std::num::ParseIntError; // 使用两种方式填空: map, and then fn add_two1(n_str: &str) -> Result<i32, ParseIntError> { n_str.parse::<i32>().map(|n| n + 2) } fn add_two2(n_str: &str) -> Result<i32, ParseIntError> { n_str.parse::<i32>().and_then(|n| Ok(n + 2)) } fn main() { assert_eq!(add_two1("4").unwrap(), 6); assert_eq!(add_two2("4").unwrap(), 6); println!("Success!") }
第五题:
use std::num::ParseIntError; // 使用 Result 重写后,我们使用模式匹配的方式来处理,而无需使用 `unwrap` // 但是这种写法实在过于啰嗦.. fn multiply(n1_str: &str, n2_str: &str) -> Result<i32, ParseIntError> { match n1_str.parse::<i32>() { Ok(n1) => { match n2_str.parse::<i32>() { Ok(n2) => { Ok(n1 * n2) }, Err(e) => Err(e), } }, Err(e) => Err(e), } } // 重写上面的 `multiply` ,让它尽量简介 // 提示:使用 `and_then` 和 `map` fn multiply1(n1_str: &str, n2_str: &str) -> Result<i32, ParseIntError> { // 实现... Ok(n1_str.parse::<i32>()? * n2_str.parse::<i32>()?) } fn print(result: Result<i32, ParseIntError>) { match result { Ok(n) => println!("n is {}", n), Err(e) => println!("Error: {}", e), } } fn main() { let twenty = multiply1("10", "2"); print(twenty); // 下面的调用会提供更有帮助的错误信息 let tt = multiply("t", "2"); print(tt); println!("Success!") }
第六题:
use std::num::ParseIntError; // 填空 type Res<T> = Result<T, ParseIntError>; // 使用上面的别名来引用原来的 `Result` 类型 fn multiply(first_number_str: &str, second_number_str: &str) -> Res<i32> { first_number_str.parse::<i32>().and_then(|first_number| { second_number_str.parse::<i32>().map(|second_number| first_number * second_number) }) } // 同样, 这里也使用了类型别名来简化代码 fn print(result: Res<i32>) { match result { Ok(n) => println!("n is {}", n), Err(e) => println!("Error: {}", e), } } fn main() { print(multiply("10", "2")); print(multiply("t", "2")); println!("Success!") }
Beta Was this translation helpful? Give feedback.
All reactions
-
第五题要求使用and_then和map,修改如下:
use std::num::ParseIntError; // 使用 Result 重写后,我们使用模式匹配的方式来处理,而无需使用 `unwrap` // 但是这种写法实在过于啰嗦.. fn multiply(n1_str: &str, n2_str: &str) -> Result<i32, ParseIntError> { match n1_str.parse::<i32>() { Ok(n1) => { match n2_str.parse::<i32>() { Ok(n2) => { Ok(n1 * n2) }, Err(e) => Err(e), } }, Err(e) => Err(e), } } // 重写上面的 `multiply` ,让它尽量简介 // 提示:使用 `and_then` 和 `map` fn multiply1(n1_str: &str, n2_str: &str) -> Result<i32, ParseIntError> { // 实现... n1_str.parse::<i32>().and_then(|n1| { n2_str.parse::<i32>().map(|n2| n1 * n2) }) } fn print(result: Result<i32, ParseIntError>) { match result { Ok(n) => println!("n is {}", n), Err(e) => println!("Error: {}", e), } } fn main() { let twenty = multiply1("10", "2"); print(twenty); // 下面的调用会提供更有帮助的错误信息 let tt = multiply("t", "2"); print(tt); println!("Success!") }
Beta Was this translation helpful? Give feedback.
All reactions
-
lala~
Beta Was this translation helpful? Give feedback.
All reactions
-
前3题,关注Result
和?
1、Result<T,E>
返回需要声明一下具体的返回类型
// 填空并修复错误 use std::num::ParseIntError; fn multiply(n1_str: &str, n2_str: &str) -> Result<i32, ParseIntError> { let n1 = n1_str.parse::<i32>(); let n2 = n2_str.parse::<i32>(); Ok(n1.unwrap() * n2.unwrap()) } fn main() { let result = multiply("10", "2"); assert_eq!(result, Ok(20)); let result = multiply("4", "2"); assert_eq!(result.unwrap(), 8); println!("Success!") }
2、?
的使用
use std::num::ParseIntError; // 使用 `?` 来实现 multiply // 不要使用 unwrap ! fn multiply(n1_str: &str, n2_str: &str) -> Result<i32, ParseIntError>{ let n1 = n1_str.parse::<i32>(); let n2 = n2_str.parse::<i32>(); Ok(n1?*n2?) } fn main() { assert_eq!(multiply("3", "4").unwrap(), 12); println!("Success!") }
3、?
的链式使用
use std::fs::File; use std::io::{self, Read}; fn read_file1() -> Result<String, io::Error> { let f = File::open("hello.txt"); let mut f = match f { Ok(file) => file, Err(e) => return Err(e), }; let mut s = String::new(); match f.read_to_string(&mut s) { Ok(_) => Ok(s), Err(e) => Err(e), } } // 填空 // 不要修改其它代码 fn read_file2() -> Result<String, io::Error> { let mut s = String::new(); File::open("hello.txt")?.read_to_string(&mut s)?; Ok(s) } fn main() { assert_eq!(read_file1().unwrap_err().to_string(), read_file2().unwrap_err().to_string()); println!("Success!") }
Beta Was this translation helpful? Give feedback.
All reactions
-
use std::num::ParseIntError; // 使用 `?` 来实现 multiply // 不要使用 unwrap ! fn multiply(n1_str: &str, n2_str: &str) -> Result<i32, ParseIntError> { Ok(n1_str.parse::<i32>()? * n2_str.parse::<i32>()?) } fn main() { assert_eq!(multiply("3", "4").unwrap(), 12); println!("Success!") }
Beta Was this translation helpful? Give feedback.
All reactions
-
如果我的函数中可能会出现两个以上不同类型的Error,怎么使用Result啊
Beta Was this translation helpful? Give feedback.
All reactions
-
文章有讲呀,使用动态对象,Box<dyn std::error::Error>
它可以接受所有类型错误
Beta Was this translation helpful? Give feedback.
All reactions
-
第五题
let n2=n2_str.parse::<i32>()?;
n1_str.parse::<i32>().map(|x| x*n2)
let n2=n2_str.parse::<i32>()?;
n1_str.parse::<i32>().and_then(|x| Ok(x*n2))
let n1=n1_str.parse::<i32>()?;
let n2=n2_str.parse::<i32>()?;
Ok(n1*n2)
Beta Was this translation helpful? Give feedback.
All reactions
-
map 和 and then什么时候讲的 闭包参数不是到后面才有吗
Beta Was this translation helpful? Give feedback.
All reactions
-
第五题这样写也能通过
fn multiply1(n1_str: &str, n2_str: &str) -> Result<i32, ParseIntError> {
n1_str.parse::().map(|n1| {
n2_str.parse::().and_then(|n2| Ok(n1*n2))})?
}
Beta Was this translation helpful? Give feedback.
All reactions
-
两个map也行
fn multiply1(n1_str: &str, n2_str: &str) -> Result<i32, ParseIntError> {
n1_str.parse::().map(|n1| {
n2_str.parse::().map(|n2| n1*n2)})?
}
Beta Was this translation helpful? Give feedback.
All reactions
-
如果有人知道 Haskell 的话,Rust 的 map 就是 Haskell 的 fmap,而 and_then 就是 Haskell 的 >>=。
fmap :: Functor f => f a -> (a -> b) -> f b
(>>=) :: Monad m => m a -> (a -> m b) -> m b
对应到 Rust 就是:
fmap[map] :
输入
- Result<i32, E>
- i32 -> f32
输出 - Result<f32, E>
(>>=)[and_then]:
输入
- Result<i32, E>
- i32 -> Result<f32, E>
输出 - Result<f32, E>
Beta Was this translation helpful? Give feedback.
All reactions
-
第五题可以用一种更加 Haskell 式(或者 Async/Await 式)的方法来写
use std::num::ParseIntError; use donotation::m; // 使用 Result 重写后,我们使用模式匹配的方式来处理,而无需使用 `unwrap` // 但是这种写法实在过于啰嗦.. fn multiply(n1_str: &str, n2_str: &str) -> Result<i32, ParseIntError> { match n1_str.parse::<i32>() { Ok(n1) => { match n2_str.parse::<i32>() { Ok(n2) => { Ok(n1 * n2) }, Err(e) => Err(e), } }, Err(e) => Err(e), } } // 重写上面的 `multiply` ,让它尽量简洁 // 提示:使用 `and_then` 和 `map` fn multiply1(n1_str: &str, n2_str: &str) -> Result<i32, ParseIntError> { m! { x <- n1_str.parse::<i32>(); y <- n2_str.parse::<i32>(); return x * y; } } fn print(result: Result<i32, ParseIntError>) { match result { Ok(n) => println!("n is {}", n), Err(e) => println!("Error: {}", e), } } fn main() { let twenty = multiply1("10", "2"); print(twenty); // 下面的调用会提供更有帮助的错误信息 let tt = multiply("t", "2"); print(tt); println!("Success!") }
Beta Was this translation helpful? Give feedback.
All reactions
-
不过作者好像没有 donotation::m
这个包,因此我们只能把 m! 宏的源码复制过来:
macro_rules! m { // return (return $r:expr ;) => { $crate::Lift::lift($r) }; // let-binding (let $p:pat = $e:expr ; $($r:tt)*) => {{ let $p = $e; m!($($r)*) }}; // const-bind (_ <- $x:expr ; $($r:tt)*) => { $x.and_then(move |_| { m!($($r)*) }) }; // bind ($binding:ident <- $x:expr ; $($r:tt)*) => { $x.and_then(move |$binding| { m!($($r)*) }) }; // const-bind ($e:expr ; $($a:tt)*) => { $e.and_then(move |_| m!($($a)*)) }; // pure ($a:expr) => { $a } } /// Lift a value inside a monad. pub trait Lift<A> { /// Lift a value into a default structure. fn lift(a: A) -> Self; } impl<A> Lift<A> for Option<A> { fn lift(a: A) -> Self { Some(a) } } impl<A, E> Lift<A> for Result<A, E> { fn lift(a: A) -> Self { Ok(a) } }
用以上源码代替 use donotation::m
即可。
Beta Was this translation helpful? Give feedback.
All reactions
-
done!
Beta Was this translation helpful? Give feedback.
All reactions
-
第五题的四种写法:
// fn multiply1(n1_str: &str, n2_str: &str) -> Result<i32, ParseIntError> { // // 实现... // n1_str.parse::<i32>().map(|n1| n1 * n2_str.parse::<i32>().unwrap()) // } // fn multiply1(n1_str: &str, n2_str: &str) -> Result<i32, ParseIntError> { // n1_str.parse::<i32>().map(|n1| { // n2_str.parse::<i32>().map(|n2| n2 * n1) // })? // 不加?的类型: Result<Result<i32, ParseIntError>, ParseIntError> // } // fn multiply1(n1_str: &str, n2_str: &str) -> Result<i32, ParseIntError> { // n1_str.parse::<i32>().map(|n1| { // n2_str.parse::<i32>().and_then(|n2| Ok(n2 * n1)) // })? // 不加?的类型: Result<Result<i32, ParseIntError>, ParseIntError> // } fn multiply1(n1_str: &str, n2_str: &str) -> Result<i32, ParseIntError> { n1_str.parse::<i32>().and_then(|n1| { n2_str.parse::<i32>().map(|n2| n2 * n1) }) }
Beta Was this translation helpful? Give feedback.
All reactions
-
done~~~
Beta Was this translation helpful? Give feedback.
All reactions
-
mark finished
Beta Was this translation helpful? Give feedback.
All reactions
-
第3题不对吧,如果有 hello.txt 文件,在main函数中unwrap_err 不就 panic 了吗?"Success!" 不能
Beta Was this translation helpful? Give feedback.
All reactions
-
一个问题,这里的?宏运算,我直接这样返回也是可以的,为啥还需要?运算,有咩有一个好的例子说明传播错误的重要性,以及?在这里面的作用。
fn divide(x: f64, y: f64) -> Result<f64, &'static str> {
if y == 0.0 {
Err("除数不能为0")
} else {
Ok(x / y)
}
}
fn calculate(x: f64, y: f64, z: f64) -> Result<f64, &'static str> {
let result1 = divide(x, y)?;
//在这里下面的两行,我直接返回divide(result1, z)调用结果也是可以的,为什么还需要多此一举?
let result2=divide(result1, z)?
result2
}
fn main() {
let result = calculate(10.0, 2.0, 0.0);
match result {
Ok(val) => println!("计算结果: {}", val),
Err(err) => println!("出错了: {}", err),
}
}
Beta Was this translation helpful? Give feedback.
All reactions
-
第一题
// 填空并修复错误 use std::num::ParseIntError; fn multiply(n1_str: &str, n2_str: &str) -> Result<i32, ParseIntError> { let n1 = n1_str.parse::<i32>(); let n2 = n2_str.parse::<i32>(); Ok(n1? * n2?) } fn main() { let result = multiply("10", "2"); assert_eq!(result, Ok(20)); let result = multiply("t", "2"); assert_eq!(result.unwrap_or(8), 8); println!("Success!") }
第二题
fn multiply(n1_str: &str, n2_str: &str) -> Result<i32, ParseIntError> { let n1 = n1_str.parse::<i32>(); let n2 = n2_str.parse::<i32>(); Ok(n1? * n2?) }
第三题
fn read_file2() -> Result<String, io::Error> { let mut s = String::new(); File::open("hello.txt")?.read_to_string(&mut s)?; Ok(s) }
第四题
fn add_two(n_str: &str) -> Result<i32, ParseIntError> { // n_str.parse::<i32>().map(|n| n + 2) n_str.parse::<i32>().and_then(|n| Ok(n + 2)) }
第五题
fn multiply1(n1_str: &str, n2_str: &str) -> Result<i32, ParseIntError> { // 实现1... /*let result = n1_str.parse::<i32>()? * n2_str.parse::<i32>()?; Ok(result)*/ // 实现2... n1_str.parse::<i32>().and_then(|n1| n2_str.parse::<i32>().map(|n2|n1 * n2)) }
第六题
type Res<T> = Result<T, ParseIntError>;
Beta Was this translation helpful? Give feedback.
All reactions
-
except the map& and_then, done
Beta Was this translation helpful? Give feedback.