Submit Search
Upload
幾個 Rust std 內可能有用的小技巧
•
0 likes
•
112 views
穎睿 梁
Follow
在 Rust Taiwan meetup 九月,介紹 Rust std 內有趣新奇的東西
Read less
Read more
Technology
Report
Share
Report
Share
1 of 77
Download now
Download to read offline
Recommended
Python learn guide
Python learn guide
robin yang
Solitaire with Greenfoot #2
Solitaire with Greenfoot #2
imacat .
Mysql的字符串函数
Mysql的字符串函数
climbtop
JavaScript 快速複習 2017Q1
JavaScript 快速複習 2017Q1
Sheng-Han Su
Scilab introduction(Scilab 介紹)
Scilab introduction(Scilab 介紹)
JIANG MING-LI
从问题开始,谈前端架构
从问题开始,谈前端架构
裕波 周
Ch2
Ch2
Alisha Smile
人机对弈编程概述
人机对弈编程概述
勇浩 赖
Recommended
Python learn guide
Python learn guide
robin yang
Solitaire with Greenfoot #2
Solitaire with Greenfoot #2
imacat .
Mysql的字符串函数
Mysql的字符串函数
climbtop
JavaScript 快速複習 2017Q1
JavaScript 快速複習 2017Q1
Sheng-Han Su
Scilab introduction(Scilab 介紹)
Scilab introduction(Scilab 介紹)
JIANG MING-LI
从问题开始,谈前端架构
从问题开始,谈前端架构
裕波 周
Ch2
Ch2
Alisha Smile
人机对弈编程概述
人机对弈编程概述
勇浩 赖
Ppt 1-50
Ppt 1-50
hungchiayang1
ncuma_邏輯與迴圈.pptx
ncuma_邏輯與迴圈.pptx
NCU MCL
Ppt 26-50
Ppt 26-50
hungchiayang1
Ch5 範例
Ch5 範例
hungchiayang1
Ch2 教學
Ch2 教學
hungchiayang1
Ch8
Ch8
Alisha Smile
Ch8 教學
Ch8 教學
hungchiayang1
Maintainable Javascript
Maintainable Javascript
Haixu (Hector) Guo
Python入門:5大概念初心者必備
Python入門:5大概念初心者必備
Derek Lee
More Related Content
Similar to 幾個 Rust std 內可能有用的小技巧
Ppt 1-50
Ppt 1-50
hungchiayang1
ncuma_邏輯與迴圈.pptx
ncuma_邏輯與迴圈.pptx
NCU MCL
Ppt 26-50
Ppt 26-50
hungchiayang1
Ch5 範例
Ch5 範例
hungchiayang1
Ch2 教學
Ch2 教學
hungchiayang1
Ch8
Ch8
Alisha Smile
Ch8 教學
Ch8 教學
hungchiayang1
Maintainable Javascript
Maintainable Javascript
Haixu (Hector) Guo
Python入門:5大概念初心者必備
Python入門:5大概念初心者必備
Derek Lee
Similar to 幾個 Rust std 內可能有用的小技巧
(9)
Ppt 1-50
Ppt 1-50
ncuma_邏輯與迴圈.pptx
ncuma_邏輯與迴圈.pptx
Ppt 26-50
Ppt 26-50
Ch5 範例
Ch5 範例
Ch2 教學
Ch2 教學
Ch8
Ch8
Ch8 教學
Ch8 教學
Maintainable Javascript
Maintainable Javascript
Python入門:5大概念初心者必備
Python入門:5大概念初心者必備
幾個 Rust std 內可能有用的小技巧
1.
幾個Ruststd內可能的⼩技巧 byKK 2019/09/28
2.
1 3 4 12 21 22 25 29 37 38 1. Title 2. Option 3.
Option::map 4. Option::and_then 5. Result 6. Result::map 7. Result::and_then 8. Result::map_err 9. Iterator 10. Iterator::fold
3.
Option<T> 可有可無
4.
map
5.
你可以這樣做 fnfn maybe_lenmaybe_len((ss:: OptionOption<<&&strstr>>))
->-> OptionOption<<usizeusize>> {{ matchmatch ss {{ SomeSome((ss)) =>=> SomeSome((ss..lenlen(()))),, NoneNone =>=> NoneNone,, }} }}
6.
或者... 其實⼤家都在這麼做?
7.
map fnfn maybe_lenmaybe_len((ss:: OptionOption<<&&strstr>>))
->-> OptionOption<<usizeusize>> {{ ss..mapmap((strstr::::lenlen)) }}
8.
map的概念是我有 ⼀個&str ⼀個fn(&str)->usize(str::len) ⼀個Option<&str> 然後我想要 fn(Option<&str>)->Option<usize>
9.
fn(&str)->usize mapfn(Option<&str>)->Option<usize>
10.
現在你知道為什麼map叫做map了map把原本對&str操作的函數 變成Option版本了
11.
為什麼要⽤map?因為這樣可以減少許多重複的操作
12.
and_then
13.
你可以這樣做 fnfn parse_to_i32parse_to_i32((ss:: &&strstr))
->-> OptionOption<<i32i32>> fnfn convert_to_u32convert_to_u32((ii:: i32i32)) ->-> OptionOption<<u32u32>> fnfn i_dont_know_whati_dont_know_what((uu:: u32u32)) ->-> OptionOption<<StringString>> fnfn homework_xhomework_x((ss:: &&strstr)) ->-> OptionOption<<StringString>> {{ letlet numbernumber == parse_to_i32parse_to_i32((ss));; ifif numbernumber..is_noneis_none(()) {{ returnreturn NoneNone;; }} letlet unsignedunsigned == convert_to_u32convert_to_u32((numbernumber..unwrapunwrap(())));; ifif unsignedunsigned..is_noneis_none(()) {{ returnreturn NoneNone;; }} i_dont_know_whati_dont_know_what((unsignedunsigned..unwrapunwrap(()))) }}
14.
錯...錯棚?
15.
and_then fnfn homework_x_homework_x_((ss:: &&strstr))
->-> OptionOption<<StringString>> {{ parse_to_i32parse_to_i32((ss)) ..and_thenand_then((convert_to_u32convert_to_u32)) ..and_thenand_then((i_dont_know_whati_dont_know_what)) }}
16.
map是把fn(T)->U 跟 Option<T> 變出 Option<U> and_then是把fn(T)-> Option<U> 跟 Option<T> 變出 Option<U>
17.
為什麼要⽤and_then?and_then的概念,在於能夠串接數個結果為Option的操作 利⽤這個特性,我們能夠在Option這個上下⽂內,作出類似錯誤處理 的功能
18.
這些性質就是傳說中的Mona...沒事
19.
看看這個? 基本是類似的概念,只是使⽤語法糖包起來,實作也有些微不同 不過就看狀況擇⼀使⽤吧 fnfn homework_x_homework_x_((ss:: &&strstr))
->-> OptionOption<<StringString>> {{ letlet ii == parse_to_i32parse_to_i32((ss))??;; letlet uu == convert_to_u32convert_to_u32((ii))??;; i_dont_know_whati_dont_know_what((uu)) }}
20.
也是可以寫成這樣啦... fnfn homework_xhomework_x((ss:: &&strstr))
->-> OptionOption<<StringString>> {{ i_dont_know_whati_dont_know_what((convert_to_u32convert_to_u32((parse_to_i32parse_to_i32((ss))??))??)) }}
21.
Result<T,E> 可對可錯
22.
map
23.
跟Option<T>::map⼀模⼀樣 如果想要下⾯這樣的邏輯時... fnfn result_lenresult_len((ss:: ResultResult<<&&strstr,,
i32i32>>)) ->-> ResultResult<<usizeusize,, i32i32>> {{ matchmatch ss {{ OkOk((ss)) =>=> OkOk((ss..lenlen(()))),, ErrErr((ee)) =>=> ErrErr((ee)),, }} }}
24.
你可以考慮使⽤Result<T,E>::map來取代 fnfn result_len_result_len_((ss:: ResultResult<<&&strstr,,
i32i32>>)) ->-> ResultResult<<usizeusize,, i32i32>> {{ ss..mapmap((strstr::::lenlen)) }}
25.
and_then
26.
跟Optional<T>::and_then⼀模⼀樣 如果想要下⾯這樣的邏輯時... fnfn parse_to_i32_rparse_to_i32_r((ss:: &&strstr))
->-> ResultResult<<i32i32,, i32i32>> fnfn convert_to_u32_rconvert_to_u32_r((ii:: i32i32)) ->-> ResultResult<<u32u32,, i32i32>> fnfn i_dont_know_what_ri_dont_know_what_r((uu:: u32u32)) ->-> ResultResult<<StringString,, i32i32>> fnfn homework_x_rhomework_x_r((ss:: &&strstr)) ->-> ResultResult<<StringString,, i32i32>> {{ letlet numbernumber == parse_to_i32_rparse_to_i32_r((ss));; ifif letlet ErrErr((ee)) == numbernumber {{ returnreturn ErrErr((ee));; }} letlet unsignedunsigned == convert_to_u32_rconvert_to_u32_r((numbernumber..unwrapunwrap(())));; ifif letlet ErrErr((ee)) == unsignedunsigned {{ returnreturn ErrErr((ee));; }} i_dont_know_what_ri_dont_know_what_r((unsignedunsigned..unwrapunwrap(()))) }}
27.
你值得擁有更好的 fnfn homework_x_rhomework_x_r((ss:: &&strstr))
->-> ResultResult<<StringString,, i32i32>> {{ parse_to_i32_rparse_to_i32_r((ss)) ..and_thenand_then((convert_to_u32_rconvert_to_u32_r)) ..and_thenand_then((i_dont_know_what_ri_dont_know_what_r)) }}
28.
或是這樣也Ok(沒問題) fnfn homework_x_rhomework_x_r((ss:: &&strstr))
->-> ResultResult<<StringString,, i32i32>> {{ letlet ii == parse_to_i32_rparse_to_i32_r((ss))??;; letlet uu == convert_to_u32_rconvert_to_u32_r((ii))??;; i_dont_know_what_ri_dont_know_what_r((uu)) }} 這個就有待商榷了 fnfn homework_x_rhomework_x_r((ss:: &&strstr)) ->-> ResultResult<<StringString,, i32i32>> {{ i_dont_know_what_ri_dont_know_what_r((convert_to_u32_rconvert_to_u32_r((parse_to_i32_rparse_to_i32_r((ss))??))??)) }}
29.
map_err
30.
你可以這樣做 fnfn homework_yhomework_y((ss:: &&strstr))
->-> ResultResult<<StringString,, StringString>> {{ letlet err_to_stringerr_to_string == ||ee|| format!format!(("got error: {}""got error: {}",, ee));; letlet numbernumber == parse_to_i32_rparse_to_i32_r((ss));; ifif letlet ErrErr((ee)) == numbernumber {{ returnreturn ErrErr((err_to_stringerr_to_string((ee))));; }} letlet unsignedunsigned == convert_to_u32_rconvert_to_u32_r((numbernumber..unwrapunwrap(())));; ifif letlet ErrErr((ee)) == unsignedunsigned {{ returnreturn ErrErr((err_to_stringerr_to_string((ee))));; }} letlet whatwhat == i_dont_know_what_ri_dont_know_what_r((unsignedunsigned..unwrapunwrap(())));; ifif letlet ErrErr((ee)) == whatwhat {{ returnreturn ErrErr((err_to_stringerr_to_string((ee))));; }} OkOk((whatwhat..unwrapunwrap(()))) }}
31.
問題來⾃於我們計算出來的是Result<T,E> 但是函數想要的回傳值是Result<T,X> 我們需要⼀個好⽅法,把Result<T,E>變成Result<T,X>!
32.
map_err fnfn homework_yhomework_y((ss:: &&strstr))
->-> ResultResult<<StringString,, StringString>> {{ letlet to_strto_str == ||ee|| format!format!(("got error: {}""got error: {}",, ee));; letlet numbernumber == parse_to_i32_rparse_to_i32_r((ss))..map_errmap_err((to_strto_str));; ifif letlet ErrErr((ee)) == numbernumber {{ returnreturn ErrErr((ee));; }} letlet unsignedunsigned == convert_to_u32_rconvert_to_u32_r((numbernumber..unwrapunwrap(())))..map_errmap_err((to_strto_str));; ifif letlet ErrErr((ee)) == unsignedunsigned {{ returnreturn ErrErr((ee));; }} letlet whatwhat == i_dont_know_what_ri_dont_know_what_r((unsignedunsigned..unwrapunwrap(())))..map_errmap_err((to_strto_str));; ifif letlet ErrErr((ee)) == whatwhat {{ returnreturn ErrErr((ee));; }} OkOk((whatwhat..unwrapunwrap(()))) }}
33.
嗯...事情看起來還是挺糟糕的
34.
⽤上之前學過的好⽤技巧後... fnfn homework_yhomework_y((ss:: &&strstr))
->-> ResultResult<<StringString,, StringString>> {{ parse_to_i32_rparse_to_i32_r((ss)) ..and_thenand_then((convert_to_u32_rconvert_to_u32_r)) ..and_thenand_then((i_dont_know_what_ri_dont_know_what_r)) ..map_errmap_err((||ee|| format!format!(("got error: {}""got error: {}",, ee)))) }} 沒錯,只要多加⼀⾏map_err,就能好好的表達意圖了
35.
使⽤?的版本,看起來效果有限 fnfn homework_y_homework_y_((ss:: &&strstr))
->-> ResultResult<<StringString,, StringString>> {{ letlet err_to_strerr_to_str == ||ee|| format!format!(("got error: {}""got error: {}",, ee));; letlet ii == parse_to_i32_rparse_to_i32_r((ss))..map_errmap_err((err_to_strerr_to_str))??;; letlet uu == convert_to_u32_rconvert_to_u32_r((ii))..map_errmap_err((err_to_strerr_to_str))??;; i_dont_know_what_ri_dont_know_what_r((uu))..map_errmap_err((err_to_strerr_to_str)) }}
36.
為什麼要⽤map_err?因為這樣可以減少許多重複的操作
37.
Iterator ⼀個⼀個來
38.
fold
39.
你⼀定這樣做過 fnfn sumsum((numsnums:: &&[[i32i32]]))
->-> i32i32 {{ letlet mutmut sumsum == 00;; forfor nn inin numsnums {{ sumsum +=+= nn;; }} sumsum }} 但是我們可以做的更好
40.
先讓我們忽略這個 fnfn sumsum((numsnums:: &&[[i32i32]]))
->-> i32i32 {{ numsnums..iteriter(())..sumsum(()) }}
41.
fold的概念是什麼?我們有⼀連串的資料,經過⼀些操作,產⽣⼀個資料
42.
⽤剛剛的sum當作例⼦,如果使⽤fold來寫,是這樣 numsnums..iteriter(())..foldfold((00,, i32i32::::addadd)) 或是 numsnums..iteriter(())..foldfold((00,, ||accacc,,
xx|| accacc ++ xx))
43.
numsnums..iteriter(())..foldfold((00,, ||accacc,, xx||
accacc ++ xx)) ⼀連串的資料=很多i ⼀些操作=加法 最後的結果=⼀個i
44.
fold真的不複雜 letlet numsnums ==
[[11,,22,,33,,44,,55]];; letlet sumsum == numsnums..iteriter(())..foldfold((00,, ||accacc,, xx|| accacc ++ xx));; 其實就是 letlet numsnums == [[11,,22,,33,,44,,55]];; letlet sumsum == ((((((((((00 ++ 11)) ++ 22)) ++ 33)) ++44)) ++ 55)) 所以我們才需要給⼀個起始值0
45.
為什麼要⽤fold?因為這樣可以減少許多重複的操作 繼續使⽤剛剛的例⼦,我們已經有了 i 這個型別 add(+)這個函數 ⼀連串的i 要完成sum,我們缺少的就是⼀個把他們組合起來的明確概念了
46.
當然for配合上⼀個mut變數可以做到⼀樣的事情 但是for並不算是⼀個明確概念,它很模糊,你甚⾄可以中途return === 明確的概念=溝通上的精確=減少錯誤產⽣的機會
47.
重點是!
48.
出錯的話就是fold的實作者的問題了,不是我XD
49.
flat_map
50.
先來說說Iterator::map就好 letlet numsnums ==
[[11,,22,,33]];; numsnums..iteriter(())..mapmap((||ee|| ee ** ee));; // 我們可以拿到 [1, 4, 9] 的 Iterator// 我們可以拿到 [1, 4, 9] 的 Iterator [1,2,3]經過運算|e|e*e變成[1,4,9],數量是不變的
51.
如果我們想要這樣做呢 [[11,,22,,33]] ->-> [[11,,
22,, 22,, 33,, 33,, 33]] 對於每個元素n,產⽣n個n 很明顯,這個並不map的⾏為,因為數量改變了
52.
過去我們可能會這樣做 letlet mutmut xx
== VecVec::::newnew(());; forfor ii inin 11..=..=55 {{ forfor __ inin 00....ii {{ xx..pushpush((ii));; }} }} 這是個可⾏的解法,但是有個很嚴重的缺點 那就是得到的結果並不是Iterator,這表⽰所有東⻄都要乖乖算完才能 得到結果
53.
我們到底想要做什麼呢 [[11,,22,,33]] =>=> [[[[11]],, [[22,,
22]],, [[33,, 33,, 33]]]] // A// A =>=> [[11,, 22,, 22,, 33,, 33,, 33]] // B// B A的部分,數量是⼀樣的,這表⽰我們可以⽤map,從i 產⽣ Iterator<i > B的部分,則是要把Iterator<Iterator<i >>變成Iterator<i >
54.
map⼤家都很熟了,就不多說 我們可以⽤iter::repeat跟take達到⽬的 fnfn repeat_nrepeat_n((nn:: u16u16))
->-> implimpl IteratorIterator<<ItemItem == u16u16>> {{ repeatrepeat((nn))..taketake((usizeusize::::fromfrom((nn)))) }} [[11,, 22,, 33]]..iteriter(())..mapmap((repeat_nrepeat_n)) // [[1], [2, 2], [3, 3, 3]]// [[1], [2, 2], [3, 3, 3]] 這樣我們就拿到Iterator的Iterator了
55.
B的部分,則是要把Iterator<Iterator<i >>變成Iterator<i > 太好了,Iterator::flatten就是這樣⽤的! fnfn
repeat_nrepeat_n((nn:: u16u16)) ->-> implimpl IteratorIterator<<ItemItem == u16u16>> {{ repeatrepeat((nn))..taketake((usizeusize::::fromfrom((nn)))) }} [[11,, 22,, 33]]..iteriter(())..mapmap((repeat_nrepeat_n)) // [[1], [2, 2], [3, 3, 3]]// [[1], [2, 2], [3, 3, 3]] [[11,, 22,, 33]]..iteriter(())..mapmap((repeat_nrepeat_n))..flattenflatten(()) // [1, 2, 2, 3, 3, 3]// [1, 2, 2, 3, 3, 3]
56.
現在你知道為什麼他叫做flat_map了! 他是計算完後,會進⾏flatten的map [[11,, 22,, 33]]..iteriter(())..flat_mapflat_map((repeat_nrepeat_n)) //
[1, 2, 2, 3, 3, 3]// [1, 2, 2, 3, 3, 3] [[11,, 22,, 33]]..iteriter(())..mapmap((repeat_nrepeat_n)) // [[1], [2, 2], [3, 3, 3]]// [[1], [2, 2], [3, 3, 3]] [[11,, 22,, 33]]..iteriter(())..mapmap((repeat_nrepeat_n))..flattenflatten(()) // [1, 2, 2, 3, 3, 3]// [1, 2, 2, 3, 3, 3]
57.
為什麼要⽤flat_map?因為這樣可以減少許多重複的操作
58.
等等...
59.
怪怪的 fnfn flat_mapflat_map((IterIter<<TT>>,, fnfn((TT))
->-> IterIter<<UU>>)) ->-> IterIter<<UU>> fnfn and_thenand_then((OptionOption<<TT>>,, fnfn((TT)) ->-> OptionOption<<UU>>)) ->-> OptionOption<<UU>> fnfn and_thenand_then((ResultResult<<TT,, EE>>,, fnfn((TT)) ->-> OptionOption<<UU,, EE>>)) ->-> OptionOption<<UU,, EE>>
60.
61.
FromIterator 通通組合起來
62.
FromIterator說起來可能有些陌⽣,但是他最常⽤的地⽅就是這個 ((11....100100))..collectcollect::::<<VecVec<<__>>>>(()) 就是那個collect 這表⽰Vec<T>有實作FromIterator<T>
63.
因為概念都⼀樣,後⾯就快速看看⽤法吧
64.
implFromIterator<(K,V)>forHashMap<K,V> letlet mapmap:: HashMapHashMap<<StringString,,
i32i32>> == [[ (("one""one"..intointo(()),, 11)),, (("two""two"..intointo(()),, 22)),, (("the_answer""the_answer"..intointo(()),, 4242)),, ]] ..iteriter(()) ..clonedcloned(()) // 要記得這個,型別才會對// 要記得這個,型別才會對 ..collectcollect(());; // HashMap 內容有// HashMap 內容有 // ("one", 1),// ("one", 1), // ("two", 2)// ("two", 2) // ("the_answer", 42)// ("the_answer", 42)
65.
implFromIterator<String>forString letlet ss:: StringString
== [[ "apple > ""apple > ",, "orange > ""orange > ",, "lemon > ""lemon > ",, ]] ..iteriter(()) ..clonedcloned(()) // 要記得這個,型別才會對// 要記得這個,型別才會對 ..mapmap((strstr::::to_stringto_string)) ..collectcollect(());; // "apple > orange > lemon > "// "apple > orange > lemon > "
66.
implFromIterator<Option<A>>forOption<V> whereV:FromIterator<A> letlet oo:: OptionOption<<VecVec<<i32i32>>>>
== [[ SomeSome((1111)),, SomeSome((1212)),, SomeSome((2424)),, ]] ..iteriter(()) ..clonedcloned(()) // 要記得這個,型別才會對// 要記得這個,型別才會對 ..collectcollect(());; // Some([11, 12, 24])// Some([11, 12, 24])
67.
implFromIterator<Option<A>>forOption<V> whereV:FromIterator<A> letlet oo:: OptionOption<<VecVec<<i32i32>>>>
== [[ SomeSome((1111)),, NoneNone,, SomeSome((2424)),, ]] ..iteriter(()) ..clonedcloned(()) // 要記得這個,型別才會對// 要記得這個,型別才會對 ..collectcollect(());; // None// None
68.
implFromIterator<Result<A,E>>forResult<V,E> whereV:FromIterator<A> letlet rr:: ResultResult<<VecVec<<i32i32>>,,
StringString>> == [[ OkOk((1111)),, OkOk((2222)),, OkOk((2424)),, ]] ..iteriter(()) ..clonedcloned(()) // 要記得這個,型別才會對// 要記得這個,型別才會對 ..collectcollect(());; // Ok([11, 22, 24])// Ok([11, 22, 24])
69.
implFromIterator<Result<A,E>>forResult<V,E> whereV:FromIterator<A> letlet rr:: ResultResult<<VecVec<<i32i32>>,,
StringString>> == [[ OkOk((1111)),, ErrErr(("Error!!""Error!!"..to_stringto_string(()))),, OkOk((2424)),, ]] ..iteriter(()) ..clonedcloned(()) // 要記得這個,型別才會對// 要記得這個,型別才會對 ..collectcollect(());; // Err("Error!!")// Err("Error!!")
70.
為什麼要⽤FromIterator?因為這樣可以減少許多重複的操作 藉由從Iterator產⽣需要的資料結構,我們就獲得了使⽤Iterator的能 ⼒例如map,filter,take_while等等 不⽌好懂,也更好維護
71.
hash_map::Entry 不只是Option
72.
你可能會這樣寫 letlet mutmut mm
== HashMapHashMap::::<<i32i32,, StringString>>::::newnew(());; ifif letlet NoneNone == mm..getget((&&4242)) {{ mm..insertinsert((4242,, "the answer""the answer"..intointo(())));; }} letlet valuevalue == mm..getget((&&4242))..unwrapunwrap(());;
73.
Entry letlet mutmut mm
== HashMapHashMap::::<<i32i32,, StringString>>::::newnew(());; letlet valuevalue == mm..entryentry((4242))..or_insert_withor_insert_with((|||| "the answer""the answer"..intointo(())));;
74.
這個api在collections裡⾯的容器幾乎都有實作
75.
為什麼要⽤FromIterator?因為這樣可以減少許多重複的操作 ⽽且少掉了unwrap的危險操作
76.
Q&A
77.
Thanks!
Download now