2 điểm bởi GN⁺ 2025-08-25 | Chưa có bình luận nào. | Chia sẻ qua WhatsApp
  • Trong Zig 0.15, giao diện IO mới (std.Io.Reader, std.Io.Writer) đã được giới thiệu
  • Mục tiêu là cải thiện độ phức tạp và các vấn đề hiệu năng của cách làm IO cũ, nhưng lại phát sinh sự bối rối trong cách sử dụng thực tế
  • Liên quan đến việc dùng tls.Clientbuffer, cách truyền tham số thiếu nhất quán càng làm tăng sự khó hiểu
  • Ngay cả khi triển khai ví dụ sử dụng cơ bản cũng có nhiều yêu cầu phức tạp như chỉ định kích thước buffer, các trường tùy chọn
  • Do thiếu tài liệu chính thức, ví dụ mã nguồn và hàm tiện ích, nên không trực quan với người mới bắt đầu

Giao diện IO mới được đưa vào Zig 0.15 và bối cảnh của nó

  • Trong Zig 0.15, các kiểu IO mới là std.Io.Readerstd.Io.Writer đã được đưa vào
  • Giao diện IO trước đây gây ra độ phức tạp do vấn đề hiệu năng, trộn lẫn kiểu và lạm dụng anytype
  • Mục tiêu chính của cấu trúc IO mới là phân tách kiểu rõ ràng giữa các giao diện và cải thiện hiệu năng

Các vấn đề thực tế khi dùng tls.Client và giao diện IO

  • Trong quá trình cập nhật thư viện smtp cũ, sự nhầm lẫn xuất hiện ở cách dùng hàm tls.Client.init
  • Theo tài liệu, hàm init nhận con trỏ tới Reader và Writer cùng một tập tùy chọn làm đối số
  • net.Stream của Zig trả về Stream.Reader/Stream.Writer thông qua các phương thức reader()writer() tương ứng
    • Tuy nhiên Stream.Reader/Stream.Writerstd.Io.Reader/std.Io.Writer không phải chính xác là cùng một kiểu, nên cần chuyển đổi
    • Với Reader phải gọi phương thức interface(), còn Writer phải dùng trường &interface, nên thiếu tính nhất quán

Vấn đề cấu hình buffer và các trường tùy chọn

  • stream.writer, stream.reader mỗi bên đều nhận buffer làm đối số
    • Buffer được nhấn mạnh là yếu tố bắt buộc trong giao diện IO mới
  • Khi gọi tls.Client.init, bắt buộc phải có bốn trường tùy chọn như ca_bundle, host, write_buffer, read_buffer
    • Quy tắc tách biệt giữa giá trị truyền qua tham số tùy chọn và giá trị truyền trực tiếp qua đối số tạo cảm giác không rõ ràng
var tls_client = try std.crypto.tls.Client.init(
  reader.interface(),
  &writer.interface,
  .{
    .ca = .{.bundle = bundle},
    .host = .{ .explicit = "www.openmymind.net"; } ,
    .read_buffer = &read_buf2,
    .write_buffer = &write_buf2,
  },
)
  • Trên thực tế, nếu không truyền đúng con trỏ buffer thì chương trình có thể không hoạt động đúng, bị treo hoặc crash, cùng nhiều vấn đề khác

Vấn đề về tính trực quan khi dùng Reader

  • Dù trường reader của tls.Client bản thân là một "luồng đã giải mã", nhưng trên thực tế std.Io.Reader lại không có phương thức read thông thường
  • Thay vào đó chỉ có các phương thức kém trực quan hơn như peek, takeByteSigned, readSliceShort
  • API gần nhất với cách sử dụng quen thuộc là đọc dữ liệu vào buffer thông qua phương thức stream
var buf: [1024]u8 = undefined;
var w: std.Io.Writer = .fixed(&buf);
const n = try tls_client.reader.stream(&w, .limited(buf.len));

Ví dụ mã đầy đủ và các vấn đề thực chiến

  • Ngay cả khi cố tạo một ví dụ tối thiểu chạy được đầy đủ, vẫn có rất nhiều điểm phải chú ý như tùy chọn, kích thước buffer, chuyển đổi kiểu
  • Thiếu test/tài liệu/ví dụ làm tăng độ khó học và rào cản tiếp cận
  • Nếu chưa hiểu rõ tính nhất quán trong ngôn ngữ Zig hoặc thiết kế nền tảng của nó, sẽ có nhiều điểm tạo cảm giác kỳ lạ
  • Ngay trong thư viện chuẩn, cách làm này cũng chưa được dùng nhiều nên thiếu tài liệu tham khảo thực tế

Kinh nghiệm và kết luận

  • Quá trình migration bản thân đã không hề dễ, do các thay đổi như đổi tên std.fmt.printInt, thay đổi thiết kế API, v.v.
  • Đã liên tục gặp nhiều khó khăn như cách reader.interface(), &writer.interface, cách truyền tùy chọn và việc cần nhiều buffer
  • Với người chưa quen các giao thức mạng/bảo mật như TLS, việc nắm bắt các yêu cầu này lại càng khó hơn
  • Tổng thể mà nói, so với trước đây vẫn còn nhiều điểm chưa hoàn thiện về độ rõ ràng, tài liệu hóa và tính tiện dụng

Chưa có bình luận nào.

Chưa có bình luận nào.