Bỏ qua để đến nội dung

In ra màn hình trong Rust

Bạn đã dùng println! khá nhiều lần rồi. Trang này giới thiệu các macro in khác mà bạn sẽ gặp, và khi nào nên dùng cái nào.

println! in chữ ra và thêm một ký tự xuống dòng ở cuối. print! làm y như vậy nhưng không thêm ký tự xuống dòng:

fn main() {
print!("Xin chào, ");
print!("thế giới");
println!("!");
}

Kết quả:

Xin chào, thế giới!
▶ Tự chạy thử

Để ý rằng cả ba lời gọi đều in trên cùng một dòng — chỉ println! mới xuống dòng mới. Trong thực tế, bạn sẽ dùng println! gần như mọi lúc; print! chủ yếu có ích khi bạn ghép một dòng từ nhiều mảnh.

Bạn đã thấy {} được dùng làm chỗ giữ chỗ (placeholder). Bạn có thể điền vào nó bằng cách truyền một giá trị sau chuỗi, hoặc đặt tên biến trực tiếp vào trong cặp ngoặc:

fn main() {
let name = "Ferris";
let age = 10;
println!("{} năm nay {} tuổi", name, age); // theo vị trí
println!("{name} năm nay {age} tuổi"); // viết trực tiếp (kết quả như nhau)
}

Kết quả:

Ferris năm nay 10 tuổi
Ferris năm nay 10 tuổi
▶ Tự chạy thử

Cả hai dòng in ra giống hệt nhau. Kiểu viết trực tiếp ({name}) mới hơn một chút và thường dễ đọc hơn, nên hãy ưu tiên nó khi có thể.

Đôi khi bạn muốn có đoạn chữ đã định dạng dưới dạng một String thay vì in ngay — chẳng hạn để lưu lại hoặc truyền cho một hàm khác. Đó là việc của format!. Nó hoạt động y hệt println! nhưng trả về một String thay vì in ra:

fn main() {
let name = "Ferris";
let message = format!("Xin chào, {name}!");
println!("{message}");
}

Kết quả:

Xin chào, Ferris!
▶ Tự chạy thử

{} thông thường chỉ dùng được cho những giá trị biết cách tự hiển thị thành chữ — số, chuỗi, boolean. Với những giá trị phức tạp hơn như tuple hay struct, {} sẽ không biên dịch được. Hãy dùng {:?} (định dạng “debug”) thay thế:

fn main() {
let point = (3, 7);
println!("{:?}", point);
}

Kết quả:

(3, 7)
▶ Tự chạy thử

Để có bố cục nhiều dòng đẹp hơn cho các giá trị lớn, hãy dùng {:#?} (pretty-print):

fn main() {
let point = (3, 7);
println!("{:#?}", point);
}

Kết quả:

(
3,
7,
)
▶ Tự chạy thử

Vài mẹo định dạng hay gặp:

fn main() {
let pi = 3.14159;
println!("{:.2}", pi); // 2 chữ số thập phân -> 3.14
println!("{:5}", 42); // độn cho đủ độ rộng 5 -> " 42"
println!("{:08.2}", pi); // độn bằng số 0 -> 00003.14
}

Kết quả:

3.14
42
00003.14
▶ Tự chạy thử

Bạn không cần học thuộc những thứ này — chỉ cần biết chúng tồn tại để dùng khi cần căn thẳng các con số hay làm tròn số thập phân.

Độ rộng cũng dùng được cho chữ, và bạn có thể chọn giá trị bám về phía nào. Sau dấu :, đặt < (trái), > (phải) hoặc ^ (giữa), rồi đến độ rộng. Bạn cũng có thể đặt một ký tự độn ở phía trước, như -:

fn main() {
let coffee = 3.5;
let bagel = 2.25;
println!("{:-^20}", " THỰC ĐƠN ");
println!("{:<12}{:>8}", "Món", "Giá");
println!("{:<12}{:>8.2}", "Cà phê", coffee);
println!("{:<12}{:>8.2}", "Bánh mì", bagel);
println!("{:<12}{:>8.2}", "Tổng", coffee + bagel);
}

Kết quả:

----- THỰC ĐƠN -----
Món Giá
Cà phê 3.50
Bánh mì 2.25
Tổng 5.75
▶ Tự chạy thử

Đọc {:>8.2} từng mảnh: > nghĩa là căn phải, 8 là độ rộng, và .2 nghĩa là hai chữ số thập phân. Căn phải các con số giúp dấu chấm thập phân thẳng hàng, đó là lý do hóa đơn và bảng biểu hay làm vậy.

Rust đếm độ rộng theo số ký tự, nên chữ tiếng Việt có dấu vẫn căn thẳng hàng bình thường.

Nếu bạn muốn in ra một dấu { thật thì sao? Vì dấu ngoặc nhọn nghĩa là “chỗ giữ chỗ”, bạn phải viết đôi chúng: {{ in ra { và }} in ra }.

fn main() {
println!("Tập hợp: {{{}, {}}}", 1, 2);
}

Kết quả:

Tập hợp: {1, 2}
▶ Tự chạy thử

Lưu tên món "Sổ tay" và giá 2.5, rồi in ra Sổ tay có giá $2.50. Gợi ý: {:.2} làm tròn đến hai chữ số thập phân, và nó cũng dùng được khi viết trực tiếp: {price:.2}.

Xem lời giải
fn main() {
let item = "Sổ tay";
let price = 2.5;
println!("{item} có giá ${price:.2}");
}

Kết quả:

Sổ tay có giá $2.50
▶ Tự chạy thử

Dùng format! để tạo nhãn ferris-7 từ tên "ferris" và số 7. In nó một lần bằng {} và một lần bằng {:?}, rồi tìm điểm khác nhau. Gợi ý: format! nhận đúng những chỗ giữ chỗ giống như println!.

Xem lời giải
fn main() {
let name = "ferris";
let id = 7;
let label = format!("{name}-{id}");
println!("{label}");
println!("{label:?}");
}

Kết quả:

ferris-7
"ferris-7"
▶ Tự chạy thử

In debug hiển thị chữ có dấu ngoặc kép, nên bạn thấy chính xác chỗ nó bắt đầu và kết thúc. Điều này rất tiện khi một giá trị có dấu cách thừa.

  • println! in kèm xuống dòng; print! thì không.
  • {} và {name} là chỗ giữ chỗ cho những giá trị có thể tự hiển thị (Display).
  • format! hoạt động như println! nhưng trả về một String thay vì in ra.
  • {:?} (và {:#?}) in giá trị để debug, kể cả những giá trị mà {} không xử lý được.
  • {:.2} làm tròn số thập phân; <, > và ^ cùng với độ rộng giúp căn lề chữ; {{ và }} in ra dấu ngoặc nhọn thật.

Kiểm tra nhanh

1. println! và print! khác nhau thế nào?

2. Vì sao nên dùng {:?} thay vì {} để in một tuple?

Điểm: 0 / 2