Setiap program Zig yang membaca atau menulis data berhadapan dengan dua antarmuka pusat pada pustaka standar, yaitu std.Io.Reader untuk sumber data dan std.Io.Writer untuk tujuan data. Topik ini membahas bentuk keduanya, peran buffer yang disediakan pemanggil, kontrak flush, serta ketiga berkas standar stdout, stdin, dan stderr. Setelah membacanya, program dapat menulis beberapa baris ke stdout melalui Writer ber-buffer dan membaca sumber data melalui Reader dengan pola yang sama untuk semua jenis sumber dan tujuan.
Konsep#
Dua antarmuka pusat std.Io#
std.Io.Writer adalah antarmuka untuk tujuan data, sedangkan std.Io.Reader adalah antarmuka untuk sumber data. Keduanya diperkenalkan pada 0.15 sebagai bagian dari perombakan I/O pustaka standar, dan sejak itu seluruh operasi keluaran-masukan Zig bergerak melalui keduanya. Antarmuka bekerja melalui tabel fungsi (vtable), yaitu sekumpulan alamat fungsi yang diisi sesuai tujuan yang sesungguhnya, sehingga satu tipe yang sama melayani stdout, berkas, memori, maupun jaringan. Karena tipe antarmukanya tunggal, fungsi bantu tidak perlu mengetahui jenis tujuan yang sedang dipakai.
Kedua antarmuka menuntut buffer, yaitu area memori sementara yang disediakan pemanggil dan dialamatkan pada antarmuka saat konstruksi. Data yang ditulis tidak langsung dikirim ke tujuan, melainkan mengisi buffer terlebih dahulu, kemudian dikirim ketika buffer penuh atau ketika flush dipanggil. Desain ini selaras dengan prinsip Zig yang menolak alokasi tersembunyi, karena ukuran memori sementara terlihat pada deklarasi array pemanggil, bukan pada keputusan diam-diam pustaka. Diagram berikut memperlihatkan lapisan tersebut pada arah penulisan.
Kode program hanya berbicara dengan antarmuka, antarmuka mengisi buffer pemanggil, dan pengiriman ke tujuan terjadi pada lapisan berikutnya. Tiga tujuan pada diagram dibentuk dengan konstruktor yang berbeda, tetapi tipe antarmukanya sama, yaitu std.Io.Writer. Arah membaca dibangun dengan cara serupa melalui std.Io.Reader, sehingga pola kode tidak berubah ketika sumber atau tujuannya diganti.
Writer ber-buffer dan kontrak flush#
Konstruksi Writer untuk stdout terdiri atas tiga langkah. Pertama, std.Io.File.stdout() menghasilkan pegangan berkas standar keluaran. Kedua, fungsi writer(io, &out_buf) pada berkas tersebut menghasilkan pembungkus yang menyimpan instance io, berkasnya, dan sebuah std.Io.Writer dengan buffer out_buf milik pemanggil. Ketiga, alamat w.interface diambil sebagai *std.Io.Writer yang menerima seluruh panggilan penulisan. Variabel out inilah yang dipakai untuk print, writeAll, dan flush.
Metode print dan writeAll hanya menyalin data ke buffer, sedangkan flush mengosongkan buffer menuju tujuan yang sebenarnya. Kontraknya tegas, yaitu data yang masih berada di buffer saat program berakhir tidak pernah tiba di tujuan. Karena itu, panggilan flush wajib dilakukan setelah seluruh penulisan selesai, biasanya satu kali di akhir fungsi main. Program berikut menulis tiga catatan sensor suhu ke stdout dengan pola tersebut.
const std = @import("std");
pub fn main(init: std.process.Init) !void {
const io = init.io;
var out_buf: [1024]u8 = undefined;
var stdout_writer = std.Io.File.stdout().writer(io, &out_buf);
const out = &stdout_writer.interface;
try out.print("sensor D3: 27.5 derajat\n", .{});
try out.print("sensor D4: 28.1 derajat\n", .{});
try out.writeAll("rata-rata: 27.8 derajat\n");
try out.flush();
}sensor D3: 27.5 derajat
sensor D4: 28.1 derajat
rata-rata: 27.8 derajatBaris pertama fungsi main mengambil instance io dari parameter init, dan baris berikutnya mendeklarasikan buffer 1024 byte dengan penanda undefined karena isinya akan diisi antarmuka. Tiga panggilan penulisan hanya mengisi buffer tersebut, sehingga tidak ada satu pun panggilan sistem yang terjadi di tengah-tengahnya. Panggilan try out.flush() pada akhir fungsi mengirim seluruh isi buffer ke stdout sekaligus, sehingga tiga baris tampil dalam satu langkah pengiriman.
Jalankan program dari direktori tempat suhu-stdout.zig berada.
# jalankan program dari direktori topik
zig run suhu-stdout.zigsensor D3: 27.5 derajat
sensor D4: 28.1 derajat
rata-rata: 27.8 derajatContoh Lengkap#
Reader sebagai sumber data#
Arah membaca memakai pola yang sama dengan arah menulis, tetapi konstruktornya reader(io, &rbuf) dan antarmukanya std.Io.Reader. Buffer berfungsi sebagai penampung data yang diambil dari sumber sebelum diolah, sehingga sumber yang lambat sekalipun tetap dapat dibaca dalam potongan kecil. Sebuah std.Io.Reader menyediakan beberapa cara pengambilan data, dan pilihannya ditentukan oleh bentuk data yang diharapkan.
// tidak-dijalankan
var rbuf: [256]u8 = undefined;
var berkas_reader = berkas.reader(io, &rbuf);
const r = &berkas_reader.interface;
const baris = try r.takeDelimiterInclusive('\n');Metode takeDelimiterInclusive mengembalikan satu potongan data hingga pembatas yang diberikan, metode readSliceShort mengisi buffer yang diberikan sebanyak mungkin lalu mengembalikan jumlah byte yang berhasil dibaca, sedangkan allocRemaining mengambil seluruh sisa data ke memori yang dialokasikan. Ketiganya dipraktikkan dengan contoh utuh pada topik operasi stream. Untuk sumber standar, std.Io.File menyediakan stdin() dan stderr() di samping stdout(), sehingga program yang membaca masukan atau menulis pesan error memakai pola konstruksi yang persis sama.
Kesalahan umum#
Kesalahan pertama adalah menganggap print dan writeAll sudah mengirim data. Kedua metode hanya mengisi buffer, sehingga program yang berakhir tanpa flush kehilangan seluruh isinya. Program pada bagian sebelumnya lolos dari jebakan ini karena memanggil flush sebelum kembali, dan satu panggilan flush di akhir main sudah cukup untuk penulisan yang beruntun.
Kesalahan kedua adalah membiarkan buffer hidup lebih pendek daripada antarmukanya. Fungsi writer dan reader hanya menyimpan alamat buffer yang diberikan, sehingga array yang dideklarasikan di dalam fungsi bantu tidak boleh dipakai untuk antarmuka yang tetap digunakan setelah fungsi itu kembali. Pilihannya ada dua, yaitu mendeklarasikan buffer pada fungsi yang memakai antarmuka sampai selesai, atau mengalokasikan buffer dari allocator yang masa hidupnya mencakup seluruh pemakaian.
Ringkasan#
std.Io.Writerdanstd.Io.Readeradalah dua antarmuka pusat I/O sejak 0.15, dengan satu tipe yang sama untuk semua tujuan dan sumber.- Buffer disediakan pemanggil saat konstruksi, sehingga ukuran memori sementara terlihat langsung di kode.
printdanwriteAllmengisi buffer, sedangkanflushmengirim isinya ke tujuan, dan data di buffer hilang apabila program berakhir tanpaflush.stdout,stdin, danstderrdiperoleh daristd.Io.Filedengan pola konstruksi yang sama.
Referensi#
- std.Io.Writer — Dokumentasi pustaka standar Zig — Antarmuka tujuan data beserta kontrak buffer dan flush-nya.
- std.Io.Reader — Dokumentasi pustaka standar Zig — Antarmuka sumber data beserta metode pengambilannya.