thảo luận Nhật kí tự học lập trình Rust - phát triển ứng dụng Desktop (Both CLI + GUI)

  • Người tạo chủ đề Người tạo chủ đề duykhanh471
  • Ngày bắt đầu Ngày bắt đầu
Cập nhật ngày 9/8

Đã viết xong organize-cli (Mất hẳn một ngày để nhận ra lỗi sai của mình) và cập nhật thêm cho tranggen-rs (Tạo static page).

Đường dẫn

Vấn đề
  • organize-cli vẫn chưa hỗ trợ lọc tệp theo kiểu tệp, ngày giờ như bản viết bằng JS của nó.
  • tranggen-rs vẫn chưa hỗ trợ được serve (live server) và build file vẫn chưa tự động cập nhật internal links như của markdown và chưa tự động chuyển hình ảnh và các thứ khác sang thư mục build - sẽ cập nhật tiếp.

Một lỗi khá khó hiểu (trong tranggen-rs), hoặc do mình đần là mình không thể chạy config cho tệp .toml dù đã làm theo hướng dẫn và thậm chí kiểm tra thêm

Một số vấn đề khác muốn tham khảo ý kiến từ các bác, xin phép tag các bác ạ và cảm ơn các bác trước: @Konstante, @small-lambda, @dtb11288
  • Với các function trả về Result thì mọi người thực hiện test sao ạ? Mình thì tính test là .is_ok() rồi chạy hiện kết quả chương trình.
  • Với chương trình organize-cli, mình tin là có thể tối ưu thêm rất nhiều xử lý số lượng tệp lớn. Ví dụ như dùng giữa String và str (Mình vẫn đang gặp vấn đề về lifetime). Nếu được mình có thể xin nhận xét code từ các bác được không? Mình cảm ơn trước ạ
 
Cập nhật ngày 9/8

Đã viết xong organize-cli (Mất hẳn một ngày để nhận ra lỗi sai của mình) và cập nhật thêm cho tranggen-rs (Tạo static page).

Đường dẫn

Vấn đề
  • organize-cli vẫn chưa hỗ trợ lọc tệp theo kiểu tệp, ngày giờ như bản viết bằng JS của nó.
  • tranggen-rs vẫn chưa hỗ trợ được serve (live server) và build file vẫn chưa tự động cập nhật internal links như của markdown và chưa tự động chuyển hình ảnh và các thứ khác sang thư mục build - sẽ cập nhật tiếp.

Một lỗi khá khó hiểu (trong tranggen-rs), hoặc do mình đần là mình không thể chạy config cho tệp .toml dù đã làm theo hướng dẫn và thậm chí kiểm tra thêm

Một số vấn đề khác muốn tham khảo ý kiến từ các bác, xin phép tag các bác ạ và cảm ơn các bác trước: @Konstante, @small-lambda, @dtb11288
  • Với các function trả về Result thì mọi người thực hiện test sao ạ? Mình thì tính test là .is_ok() rồi chạy hiện kết quả chương trình.
  • Với chương trình organize-cli, mình tin là có thể tối ưu thêm rất nhiều xử lý số lượng tệp lớn. Ví dụ như dùng giữa String và str (Mình vẫn đang gặp vấn đề về lifetime). Nếu được mình có thể xin nhận xét code từ các bác được không? Mình cảm ơn trước ạ
theo ý của mình thì tùy vào mục đích của bạn mà mình viết test thôi, nếu bạn chỉ quan tâm hàm ko phát sinh lỗi thì cứ assert!(a.is_ok()) hoặc cứ unwrap thôi, test mà, bận tâm gì đâu, còn nếu muốn ra kết quả chính xác thì unwrap rồi assert hoặc matching assert_eq(result, Ok(abc))

còn cái organize kia thì theo ngu ý của mình, bạn build trước cái đống desination path trước, đặt trong 1 cái HashMap<FileType, String> (String hay PathBuf) gì đó, rồi bạn chỉ cần get(&AUDIO).unwrap(), kiểu vậy, đỡ phải gọi lại hàm set_dst mỗi file
còn tăng performance thì mình nghĩ cái bạn xài lib rayon ấy, multi threads
 
Sửa lần cuối:
theo ý của mình thì tùy vào mục đích của bạn mà mình viết test thôi, nếu bạn chỉ quan tâm hàm ko phát sinh lỗi thì cứ assert!(a.is_ok()) hoặc cứ unwrap thôi, test mà, bận tâm gì đâu, còn nếu muốn ra kết quả chính xác thì unwrap rồi assert hoặc matching assert_eq(result, Ok(abc))
Nhưng giả sử function của mình thực hiện tạo file và không trả về kết quả. nó chỉ kiểu Result<(), std::io:Error> thì mình muốn kiểm tra xem tệp mình tạo đã chính xác chưa kể cả khi trả về Ok(()) thì thường trong trường hợp đó bạn xử lý thế nào
còn cái organize kia thì theo ngu ý của mình, bạn build trước cái đống desination path trước, đặt trong 1 cái HashMap<FileType, String> (String hay PathBuf) gì đó, rồi bạn chỉ cần get(&AUDIO).unwrap(), kiểu vậy, đỡ phải gọi lại hàm set_dst mỗi file
Mình chưa thử cái này bao giờ, để mình đọc lại xem
 
Nhưng giả sử function của mình thực hiện tạo file và không trả về kết quả. nó chỉ kiểu Result<(), std::io:Error> thì mình muốn kiểm tra xem tệp mình tạo đã chính xác chưa kể cả khi trả về Ok(()) thì thường trong trường hợp đó bạn xử lý thế nào
thế thì bạn kiểm tra nội dung cái file thôi chứ quan trọng gì cái is_ok(), thường thì mình copy 1 file (expected file) đọc nội dung file này và file được tạo ra, giống nhau là đc, hoặc đơn giản hơn bạn kiểm tra có file được tạo ra trong thư mục đó là đc (mà trước khi gọi hàm kiểm tra là ko có file trước)
 
Nhưng giả sử function của mình thực hiện tạo file và không trả về kết quả. nó chỉ kiểu Result<(), std::io:Error> thì mình muốn kiểm tra xem tệp mình tạo đã chính xác chưa kể cả khi trả về Ok(()) thì thường trong trường hợp đó bạn xử lý thế nào

Mình chưa thử cái này bao giờ, để mình đọc lại xem

Do bạn swallow hết result của std::io rồi return void thôi. Thường thì create sẽ trả về Result<File>, write sẽ trả về Result<usize>, rất nhiều dev assert ngay đoạn code impl luôn chứ ko unit test.


Mấy cái example ngta assert contents, nhưng bạn có thể assert len.
 
Hóng, cũng mới học Rust vài ngày. Thấy chỗ Option<T> này hay ho, giống Maybe trong elm.
 
Hóng, cũng mới học Rust vài ngày. Thấy chỗ Option<T> này hay ho, giống Maybe trong TY
T mất gần 1 tháng rưỡi để ngấm được đến chương 15 của The Book, thấy mình thất bại v. Phải mất một thời gian dài mới hiểu được một chút á bác.

Nghịch lâu rồi nhưng chưa dùng Generic bao giờ T_T, mới nghịch đến Trait với impl cho các Struct khác nhau. Mà Option<T> ý bác là sao, ý là chỉ dừng lại ở kết quả trả về hay bác còn làm những kiểu impl phức tạp hơn :)) newbie rust nên bác gạch đá các thứ oke nha
 
T mất gần 1 tháng rưỡi để ngấm được đến chương 15 của The Book, thấy mình thất bại v. Phải mất một thời gian dài mới hiểu được một chút á bác.

Nghịch lâu rồi nhưng chưa dùng Generic bao giờ T_T, mới nghịch đến Trait với impl cho các Struct khác nhau. Mà Option<T> ý bác là sao, ý là chỉ dừng lại ở kết quả trả về hay bác còn làm những kiểu impl phức tạp hơn :)) newbie rust nên bác gạch đá các thứ oke nha
Mình cũng newbie rust.
Chỗ Option<T>, mình thấy hay là nó giúp mình có thể xử lý những trường hợp mà giá trị của nó có thể là null (nil). Ví dụ mình có 1 stack s của các giá trị integer, khi stack rỗng, thì s.pop() sẽ không có giá trị.
C-like:
match s.pop() {
  None -> println!("None")
  Some(x) -> println("Handle {x}")
}
Ref: std::option - Rust (https://doc.rust-lang.org/std/option/index.html)
 
Mình cũng newbie rust.
Chỗ Option<T>, mình thấy hay là nó giúp mình có thể xử lý những trường hợp mà giá trị của nó có thể là null (nil). Ví dụ mình có 1 stack s của các giá trị integer, khi stack rỗng, thì s.pop() sẽ không có giá trị.
C-like:
match s.pop() {
  None -> println!("None")
  Some(x) -> println("Handle {x}")
}
Ref: std::option - Rust (https://doc.rust-lang.org/std/option/index.html)
Cái hay của Option là bạn ko phải check từng option xem None hay ko mà là dùng các function như map, and_then, and, or, zip, unwrap_or v.v... kết hợp với nhau, phần check None thì các function này đã xử lí bên trong rồi, mình ko phải quan tâm nữa. Bỏ mấy function này đi thì Option nó cũng chỉ là 1 enum hết sức bình thường, bạn tự viết 1 cái cũng đc.

Tương tự cho các type khác như Future, Vec, Result.

Mình thấy bạn học Elm chắc cũng thích Functional programming nhỉ, bạn có thể tìm hiểu thêm về Functor, Monad v.v... để hiểu tại sao lại có các function như map, and_then chẳng hạn.

Còn rộng hơn nữa thì xem Category theory.

Ấy là mình chém gió vậy thôi, chứ cũng gà mờ lắm, kiến thức cóp nhặt ko ra đầu đuôi :D
 
Nói về category theory, trước mình có một comment trên HN về cuốn "The Dao of Functional Programming" (và được upvote vài lần) như sau:
I will get down-vote for sure but it's trivial this book and also the series "category theory for programmers". It's actually not very far from the content of several first pages of any book on set theory or logics.
I find the ubiquitous idea is that "category theory" is more prestigous than "set theory", and some programmers, instead of seriously learning mathematics, think that learning category theory would fill up their lack of knowledge (in mathematics). It's quite contrary since category theory alone (i.e. without context) is trivial.

Let's be honest: read this book and the series of the author, and try to use the acquired knowledge to prove some (even simple) mathematical theorems.

Có người trả lời lại:
and some programmers, instead of seriously learning mathematics, think that learning category theory would fill up their lack of knowledge (in mathematics). It's quite contrary since category theory alone (i.e. without context) is trivial.
High applauds for this part.

Category Theory, by design, attempts to be more general, more basic and more abstract.

1. You cannot learn the more abstract stuff first. You have to learn the special cases first- i.e. Calculus, Set Theory, Analysis, etc. You do not start studying Physics with General Relaitivity or Quantum Mechanics because they are more general. You learn them after long years of studuying special Physics of fluid motion, Newton's Law. One should not think that one can simply get a "shortcut" to the most general thing there is, without learning the special cases.

2. A lot of more general sciences are indeed special cases. When you are asked to find the set of points in a certain domain where the derivative of a function cannot be found, you are not actually doing Set Theory. You are doing Calculus.

I believe that the notion one can learn the abstract cases just by studying the abstract science is laughably wrong. They better study Theology. Shouting out "Monad is a monoid in a category of endofunctors" doesn’t teach you Math.

However, let me end this comment and rant with a book suggestion.

Please read "Seven Sketches of Composionality" if are looking for books to learn Category Theory.
 
Topic hay, chấm hóng, mới bắt đầu nhảy vào Rust mấy ngày gần đây do nghỉ lễ ngồi xem vid của Primeagen quá nhiều. Lội voz không thấy nhiều thread bàn về Rust nên còm phát đá thớt. Bác chủ thớt hay chuyển thread này qua thành kiểu hội anh em Rust đi bác :byebye: .
 
Điểm danh ké thread, ngày lễ Quốc Khánh cũng là ngày thứ 3 học Rust nhưng vẫn đang bì bõm mấy chương đầu của cuốn Rust Book, đọc mấy bác thảo luận ở trên chả hiểu gì nhưng vẫn đọc, sau khi ngâm xong sẽ quay lại đọc mấy # trước xem có hiểu không :byebye:.
 
Topic hay, chấm hóng, mới bắt đầu nhảy vào Rust mấy ngày gần đây do nghỉ lễ ngồi xem vid của Primeagen quá nhiều. Lội voz không thấy nhiều thread bàn về Rust nên còm phát đá thớt. Bác chủ thớt hay chuyển thread này qua thành kiểu hội anh em Rust đi bác :byebye: .
Năm nay ổng chuyển qua code Golang rồi đấy thím. Kêu là muốn đổi gió.
 
Cập nhật ngày 9/8

Đã viết xong organize-cli (Mất hẳn một ngày để nhận ra lỗi sai của mình) và cập nhật thêm cho tranggen-rs (Tạo static page).

Đường dẫn

Vấn đề
  • organize-cli vẫn chưa hỗ trợ lọc tệp theo kiểu tệp, ngày giờ như bản viết bằng JS của nó.
  • tranggen-rs vẫn chưa hỗ trợ được serve (live server) và build file vẫn chưa tự động cập nhật internal links như của markdown và chưa tự động chuyển hình ảnh và các thứ khác sang thư mục build - sẽ cập nhật tiếp.

Một lỗi khá khó hiểu (trong tranggen-rs), hoặc do mình đần là mình không thể chạy config cho tệp .toml dù đã làm theo hướng dẫn và thậm chí kiểm tra thêm

Một số vấn đề khác muốn tham khảo ý kiến từ các bác, xin phép tag các bác ạ và cảm ơn các bác trước: @Konstante, @small-lambda, @dtb11288
  • Với các function trả về Result thì mọi người thực hiện test sao ạ? Mình thì tính test là .is_ok() rồi chạy hiện kết quả chương trình.
  • Với chương trình organize-cli, mình tin là có thể tối ưu thêm rất nhiều xử lý số lượng tệp lớn. Ví dụ như dùng giữa String và str (Mình vẫn đang gặp vấn đề về lifetime). Nếu được mình có thể xin nhận xét code từ các bác được không? Mình cảm ơn trước ạ
  • Phần test thì phụ thuộc vào bác muốn làm gì, chứ is_ok chỉ là function hỗ trợ kiểm qua nhanh result type hay không thôi. Có thể kiểm tra exists của file đc rồi, và đặt niềm tin vào OS sẽ handle move file đúng.
  • Phần code Rust thì nên làm 1 Error tổng để handle các error con của bác, dùng From trait implement cho các error mà mình muốn handle. Sau này cần thì check type Error cũng dễ. Kiểu như

Mã:
pub enum MyError {
    AError(AError),
    BError(BError),
}

impl From<AError> for MyError {
    fn from(value: AError) -> Self { Self::AError(value) }
}

fn example_fn() -> Result<(), MyError> {
    let result = fn_will_raise_a_error()?;
    Ok(result)
}

- Về String và str, bạn nên dùng &str là tốt nhất, vụ conflict lifetime thì thường do có nhiều hơn 1 lifetime trong 1 function, fix bằng cách declare rõ ràng lifetime là được rồi.

- Tip để improve Rust code, lúc bạn declare 1 function nào đó, thì bạn cứ nghĩ là parameter đó có cần thiết phải có type đó ko? Ví dụ nếu bạn phân vân giữa String và &str -> thì bạn sẽ hỏin có thật sự cần String ko, nếu ko thì cứ dùng &str thôi. Hoặc Vec<T> và &Vec<T> thì bạn cứ nghĩ là có thật sự cần Vec<T> ko, hay mình chỉ cần đọc data -> &Vec<T> là được rồi. Từ đó các function của bạn sẽ đc tinh gọn.
 
  • Phần test thì phụ thuộc vào bác muốn làm gì, chứ is_ok chỉ là function hỗ trợ kiểm qua nhanh result type hay không thôi. Có thể kiểm tra exists của file đc rồi, và đặt niềm tin vào OS sẽ handle move file đúng.
  • Phần code Rust thì nên làm 1 Error tổng để handle các error con của bác, dùng From trait implement cho các error mà mình muốn handle. Sau này cần thì check type Error cũng dễ. Kiểu như

Mã:
pub enum MyError {
    AError(AError),
    BError(BError),
}

impl From<AError> for MyError {
    fn from(value: AError) -> Self { Self::AError(value) }
}

fn example_fn() -> Result<(), MyError> {
    let result = fn_will_raise_a_error()?;
    Ok(result)
}

- Về String và str, bạn nên dùng &str là tốt nhất, vụ conflict lifetime thì thường do có nhiều hơn 1 lifetime trong 1 function, fix bằng cách declare rõ ràng lifetime là được rồi.

- Tip để improve Rust code, lúc bạn declare 1 function nào đó, thì bạn cứ nghĩ là parameter đó có cần thiết phải có type đó ko? Ví dụ nếu bạn phân vân giữa String và &str -> thì bạn sẽ hỏin có thật sự cần String ko, nếu ko thì cứ dùng &str thôi. Hoặc Vec<T> và &Vec<T> thì bạn cứ nghĩ là có thật sự cần Vec<T> ko, hay mình chỉ cần đọc data -> &Vec<T> là được rồi. Từ đó các function của bạn sẽ đc tinh gọn.
hay quá bác.

via theNEXTvoz for iPhone
 
- Về String và str, bạn nên dùng &str là tốt nhất, vụ conflict lifetime thì thường do có nhiều hơn 1 lifetime trong 1 function, fix bằng cách declare rõ ràng lifetime là được rồi.
Khoan đã, nó lên là String khi khả năng xử lý lifetime chứ bác, trừ khi các giá trị mình lấy vào trong một function hoặc trả ra thì mình mới để &str, còn lại luôn là String khi đóng trong Enum hoặc tạo Struct
  • Phần test thì phụ thuộc vào bác muốn làm gì, chứ is_ok chỉ là function hỗ trợ kiểm qua nhanh result type hay không thôi. Có thể kiểm tra exists của file đc rồi, và đặt niềm tin vào OS sẽ handle move file đúng.
Phần này thì mình gần đây mới học được là mọi người thường hay trả về giá trị theo kiểu Result<(), một kiểu Error bất kì tại đây
 
Khoan đã, nó lên là String khi khả năng xử lý lifetime chứ bác, trừ khi các giá trị mình lấy vào trong một function hoặc trả ra thì mình mới để &str, còn lại luôn là String khi đóng trong Enum hoặc tạo Struct

Phần này thì mình gần đây mới học được là mọi người thường hay trả về giá trị theo kiểu Result<(), một kiểu Error bất kì tại đây
Uhm, phần struct thì nếu dùng String sẽ đỡ vất vả về mặt lifetime. Mình đang nói về cách tổ chức function sao cho nó tiện.

Error bất kì thì chỉ hợp với App general, có nhiều library và error khó handle hết. Còn lại nếu ít Error, hoặc trong khả năng, nên wrap type lại. Lý do sau này cần handle cũng dễ. LÚc đó chỉ cần dùng matching pattern là sẽ handle rất tiện, type rõ ràng. Còn nếu dùng Error general thì nó hơi hide đi Error Type. Bạn nên nghĩ Error là 1 type cụ thể như i32, i64, String thì sau này sẽ đỡ vất vả handle hơn. Ví dụ:


Mã:
let res: Result<(), MyError> = fn_random();
match res {
    Ok(()) => println!("Good"),
    Err(MyError:AError) => println!("Handle AError here"),
    Err(e) => println!("Unexpected Error {:?}", e),
}

// Hoặc ví dụ web app
pub enum WebAppError {
    BadRequest(String),
    InternalServerError,
}
// Send Error to CLient
match some_error {
    WebAppError::BadRequest(reason) => res.status_code(400).text(reason),
    WebAppError::InternalServerError => res.status_code(500).text("Oh no")
}
 

Thống kê chủ đề

Ngày tạo
duykhanh471,
Người trả lời cuối
emlameo4`,
Trả lời
142
Lượt xem
27.186
Quay lại
Lên đầu trang