johndo100
Senior Member
Chịu bạn ạ, mình thấy golang syntax+keyword nhìn nó sáng sủa gần gũi thì mình học thôi.Rust với Golang
Con nào ngon hơn nhể các bác?
Chịu bạn ạ, mình thấy golang syntax+keyword nhìn nó sáng sủa gần gũi thì mình học thôi.Rust với Golang
Con nào ngon hơn nhể các bác?
Hình như Rust cho performance tối ưu hơnChịu bạn ạ, mình thấy golang syntax+keyword nhìn nó sáng sủa gần gũi thì mình học thôi.
À do tui không học theo chương trình nên thấy khó. Golang nó bắt khai báo type nên code mỏi tay hơn tí nhưng khi cần nhìn biết ngay input của function là cái gì, vì cái đấy nên tui mới học nó.Chúng nó lừa đấy, trần đời mà dễ học chỉ có js, thế nên js mới lắm tai họa.

Well. It depends.Hình như Rust cho performance tối ưu hơn
các hạ cao minh quá, cho em xin roadmap go được không PHP cùi quáWell. It depends.
Nhắc đến go là nhắc đến concurrent. Rust là memory safe. Tuỳ bài toán mà áp dụng chứ nói về perf tối ưu nhất thì ai cũng viết assembly rồi.
Perf mấy thằng này same same nhau thôi. Code web không thấy khác biệt.
Btw, Go dùng xử lý concurrent vẫn nhanh hơn nhé.
Có ngay Learn to become a Go developer (https://roadmap.sh/golang)các hạ cao minh quá, cho em xin roadmap go được không PHP cùi quá
@duykhanh471 thằng này làm desktop app cross platform ngon không thím? Framework, tool cộ các thứ mature hết chưa?
Không liên quan nhưng bác đã đọc bài #1 chưa, mình có ghi là không thảo luận ưu nhược điểm của các ngôn ngữ mà. Khá cầu toàn nhưng có Thread Rust tổng bàn mấy cái như của bạn nên bạn ném sang đó nhagiờ thấy Zig khá hay, đơn giản như Golang, tốc độ nhanh hơn C, compile nhanh hơn Rust
coi thử lịch sử post đi, comment troll ghẻ khôngKhông liên quan nhưng bác đã đọc bài #1 chưa, mình có ghi là không thảo luận ưu nhược điểm của các ngôn ngữ mà. Khá cầu toàn nhưng có Thread Rust tổng bàn mấy cái như của bạn nên bạn ném sang đó nha
coi thử lịch sử post đi, comment troll ghẻ không
)) cái gì đấy bác
buukuru (https://codeberg.org/duykhanh471/buukuru)use std::{ffi::OsStr, fs::DirEntry, path::{Path, PathBuf}, vec};
use crate::checker::ImageProcessor;
pub fn check_img_format(filename: &Path) -> bool {
let image_format: Vec<&str> = vec!["jpg", "jpeg", "jpe", "jfif", "jfi", "jif", "png", "bmp", "gif"];
filename.extension().and_then(OsStr::to_str).is_some_and(|ext| image_format.contains(&ext))
}
pub fn image_filter(paths: impl IntoIterator<Item = Result<DirEntry, std::io::Error>>) -> Result<Vec<PathBuf>, std::io::Error> {
paths.into_iter()
.map(|f| f.map(|p| p.path()))
.filter(|p| p.as_ref().is_ok_and(|f| check_img_format(&f))).collect()
}
pub fn image_processing(paths: impl Iterator<Item = PathBuf>, img_processor: ImageProcessor) {
for current_path in paths {
if let Some(broken_img) = img_processor.check_broken_image(¤t_path) {
println!("Image: {:?} | {}", broken_img.path, broken_img.err_msg);
}
}
}
check_broken_image trong checker.rs có thể tham số hóa thành kiểucheck_broken_image<P: AsRef<Path> + Copy>(&self, img_path: P) -> Option<BrokenImageInfo<P>>main giờ không có kiểm tra lỗi cho panic khi unwrap, thím có thể bỏ luôn unwrap đi bang cách thêm kiểu trả về cho main. Ví dụ thế này:fn main() -> Result<(), impl Error> {
let imgs = fs::read_dir("./")?;
let img_processor = checker::ImageProcessor {};
image_processing(image_filter(imgs)?.into_iter(), img_processor);
Ok::<_, std::io::Error>(())
}
use std::{error::Error, fs};
use utils::{image_filter, image_processing};
mod checker;
mod utils;
fn main() -> Result<(), impl Error> {
let imgs = fs::read_dir("./")?;
let img_processor = checker::ImageProcessor {};
image_processing(image_filter(imgs)?.into_iter(), img_processor);
Ok::<_, std::io::Error>(())
}
use std::{fs, path::Path};
pub struct BrokenImageInfo<P> {
pub path: P,
pub err_msg: String
}
#[derive(Debug, Clone)]
pub struct ImageProcessor {}
impl ImageProcessor {
pub fn check_broken_image<P: AsRef<Path> + Copy>(&self, img_path: P) -> Option<BrokenImageInfo<P>>{
if let Err(e) = image::open(img_path) {
let error_string = e.to_string();
if error_string.contains("spectral selection is not allowed in non-progressive scan") {
println!("Skipped");
}
Some(BrokenImageInfo {
path: img_path,
err_msg: error_string,
})
} else {
None
}
}
pub fn delete_img<P: AsRef<Path>>(&self, path: P) {
fs::remove_file(path).expect("");
}
}
use std::{ffi::OsStr, fs::DirEntry, path::{Path, PathBuf}, vec};
use crate::checker::ImageProcessor;
pub fn check_img_format(filename: &Path) -> bool {
let image_format: Vec<&str> = vec!["jpg", "jpeg", "jpe", "jfif", "jfi", "jif", "png", "bmp", "gif"];
filename.extension().and_then(OsStr::to_str).is_some_and(|ext| image_format.contains(&ext))
}
pub fn image_filter(paths: impl IntoIterator<Item = Result<DirEntry, std::io::Error>>) -> Result<Vec<PathBuf>, std::io::Error> {
paths.into_iter()
.map(|f| f.map(|p| p.path()))
.filter(|p| p.as_ref().is_ok_and(|f| check_img_format(&f))).collect()
}
pub fn image_processing(paths: impl Iterator<Item = PathBuf>, img_processor: ImageProcessor) {
for current_path in paths {
if let Some(broken_img) = img_processor.check_broken_image(¤t_path) {
println!("Image: {:?} | {}", broken_img.path, broken_img.err_msg);
}
}
}
Không liên quan lắm nhưng nếu đã thêmĐịnh làm pull request nhưng lằng nhằng quá, gửi thím vài comment cho badpeggy: không nên đổi qua lại giữa PathBuf và String (hai cái này sử dụng cho hai mục đích khác nhau). Ví dụ file utils.rs thím có thể viết như sau
impl IntoIterator thì không cần chuyển sang iterator nữa
into_iter() hoặc có thể đang có nhiều hơn 1 ReadDir (Nếu mình nhớ không nhầm thì chỉ có một và nếu gọi nó ra thì nó sẽ trả Result<DirEntry, io:Error>)image_filter(paths: impl IntoIterator<Item = Result<DirEntry, std::io::Error>>) -> Result<Vec<PathBuf>, std::io::Error> {
paths.into_iter()
is_some_and(), trước trong Forum có ông bảo dùng filter_map() cũng chỉ lấy các giá trị trả về Some.pub fn check_img_format(filename: &Path) -> bool {
let image_format: Vec<&str> = vec!["jpg", "jpeg", "jpe", "jfif", "jfi", "jif", "png", "bmp", "gif"];
filename.extension().and_then(OsStr::to_str).is_some_and(|ext| image_format.contains(&ext))
}
pub fn check_img_format(filename: &Path) -> bool {
static IMAGE_FORMAT: &[&'static str; 9] = &[
"jpg", "jpeg", "jpe", "jfif", "jfi", "jif", "png", "bmp", "gif",
];
filename.extension().and_then(OsStr::to_str).is_some_and(|ext| IMAGE_FORMAT.contains(&ext))
}
use std::sync::LazyLock;
static IMAGE_FORMAT_SET: LazyLock<std::collections::HashSet<&'static str>> = LazyLock::new(|| {
HashSet::from([
"jpg", "jpeg", "jpe", "jfif", "jfi", "jif", "png", "bmp", "gif",
])
});
Không phải, thứ nhất "nhưng nếu đã thêm" là một cách dùng từ sai, vì dùng impl là cách để giảm các ràng buộc cho tham số (mà không phải là tăng): lúc đầu hàm yêu cầu tham số là một ReadDir, nhưng logic của hàm chỉ là một vòng lặp duy nhất qua tất cả các entry (có kiểu DirEntry), nên tham số chỉ cần là một kiểu bất kỳ có cài đặt trait IntoIterator.Không liên quan lắm nhưng nếu đã thêmimpl IntoIteratorthì không cần chuyển sang iterator nữa![]()
into_iter()hoặc có thể đang có nhiều hơn 1 ReadDir (Nếu mình nhớ không nhầm thì chỉ có một và nếu gọi nó ra thì nó sẽ trảResult<DirEntry, io:Error>)
- "Một ví dụ khác là vector không phải là Iterator, nó chỉ cài đặt trait IntoIterator (và Iterator)": Tức là về cơ bản thì mình nên coi (Nó đúng là vậy chứ không hẳn là nên coi) Iterator là một Trait trong bất kì một dãy kiểu dữ liệu kiểu nhưThứ hai, vẫn phải chuyển sang Iterator (bằng lời gọi .into_iter()) vì paths ở đây không phải là một Iterator, nó chỉ là một kiểu có cài đặt trait IntoIterator
Vec đúng không bác?Mặc dù hơi ngu nhưng giờ mình mới biết thêm là nếu chạy trên một số lượng lớn dữ liệu thì kết quả khác hơn thật. Tức là mỗi lần mình gọiSẽ được gọi nhiều lần (mỗi lần cho một file), và image_format nói chung là một vector không thay đổi (chứa các image extensions).
check_image() thì đồng nghĩa với việc let khởi tạo lại dãy IMAGE_FORMAT. Vậy thì liệu dùng const có tốt hơn là sử dụng &'static str (Hình như cái này (&'static) dính lifetime đúng không bác) hoặc HashMap ở trên không? Vì định dạng ảnh sẽ không thay đổi.Tại sao lại không sử dụng std::io:Error ở đây vậy fen? Mình có thử đọc khá nhiều code thì thấy nhiều người dùngfn main() -> Result<(), impl Error> {
anyhow hoặc Box dyn.async fn thì phải chỉnh giá trị trả về thành impl <Future.... (Mình sẽ tự tìm hiểu thêm tiếp, tự nhiên ngồi viết câu trả lời thì nghĩ ra)Việc sử dụng AsRef ở đây để hỗ trợ Borrowing cho Generic đúng không bác. Mình đọc Thread này trên StackOverflow thì thấy bác ấy giải thích là việc sử dụngpub fn check_broken_image<P: AsRef<Path> + Copy>(&self, img_path: P) -> Option<BrokenImageInfo<P>>{
AsRef được impl dưới dạng trait để hỗ trợ cho cả biến đấy được sử dụng kiểu &User thay vì là &user.name (Phải khai báo user và sử dụng & - Cái này có phải sử dụng #(Copy) đầu tên struct đúng không bác).Khá lạ nhưng đóng map() hai lần thì bác vẫn chuyển.map(|f| f.map(|p| p.path()))
DirEntry qua PathBuf được mà vẫn giữ được Result.Mình nhìn là.filter(|p| p.as_ref().is_ok_and(|f| check_img_format(&f))).collect()
p thuộc kiểu &Result<PathBuf, std::io::Error>, tức là ở đây khi dùng as_ref() thì sẽ chỉ lấy PathBuf dưới dạng &PathBuf và không động chạm gì đến phần còn lại của Result?impl<T> AsRef<T> không bác? (Hỏi ngu tiếp)