Binary comprehension dan iodata

Binary comprehension untuk pembangunan binary efisien dan penghematan iolist.

Daftar isi

Topik ini menuntaskan dua alat pembangunan data biner: binary comprehension yang mengubah binary menjadi binary dengan satu ekspresi, dan iodata beserta iolist yang membiarkan potongan teks tetap bersarang sampai titik perakitan terakhir. Keduanya mengikuti prinsip modul Rekursi dan list, yaitu membangun dari yang murah lalu meratakan sekali di akhir.

Binary comprehension#

Notasi [Ekspresi || Generator] untuk list memiliki pasangan binary berbentuk << <<Segmen>> || Pola <= Binary >>, dengan generator memakai <= alih-alih <-. Segmen pada bagian depan wajib menyatakan ukurannya bila isinya hasil hitungan:

erlang Transformasi binary dengan comprehension
Erlang/OTP 29 [erts-17.1.1] [source] [64-bit] [smp:2:2] [ds:2:2:10] [async-threads:1] [jit:ns]

Eshell V17.1.1 (press Ctrl+G to abort, type help(). for help)
1> << <<(X * 2):8>> || <<X>> <= <<1, 2, 3>> >>.
<<2,4,6>>
2> << <<X>> || <<X:4>> <= <<16#12, 16#34>> >>.
<<1,2,3,4>>
3> << <<(X * 2):16>> || <<X>> <= <<1, 2, 3>> >>.
<<0,2,0,4,0,6>>

Baris pertama menggandakan setiap byte dengan ukuran 8 bit eksplisit. Baris kedua memecah dua byte menjadi empat kelompok 4 bit, dan baris ketiga menunjukkan akibat ukuran: hasil 16-bit mengemas setiap nilai menjadi dua byte, sehingga keluarannya enam byte dengan byte bernilai nol di depan setiap nilai. Ukuran pada segmen hasil adalah bagian dari spesifikasi, bukan detail. Tanpa tanda kurung dan ukuran yang sesuai, compiler menolak ekspresinya dengan error konstruksi binary. Penyaringan juga bekerja sama seperti list comprehension:

erlang Penyaringan byte genap
4> << <<X>> || <<X>> <= <<1, 2, 3, 4>>, X rem 2 =:= 0 >>.
<<2,4>>

Kondisi pada generator menyisakan byte genap saja, dan hasilnya tetap binary, bukan list. Generatornya sendiri boleh menyatakan ukuran, sebagaimana <<X:4>> pada baris kedua sesi pertama yang mengambil empat bit per iterasi, sehingga pemecahan dan penyaringan terjadi dalam satu ekspresi tanpa variabel perantara.

Iodata dan iolist#

Menyambung binary besar dengan ++ atau pembangunan berulang sama mahalnya dengan list, karena setiap sambungan menyalin. Erlang menyediakan jalan lain: struktur bersarang berisi binary, byte, dan list yang disebut iodata, yang diterima langsung oleh fungsi keluaran tanpa diratakan lebih dulu. Iodata dalam bentuk list penuh sering disebut iolist:

erlang Menyatukan iodata sekali di akhir
4> iolist_to_binary([<<"halo">>, [" ", <<"dunia">>]]).
<<"halo dunia">>
5> iolist_size([<<"halo">>, [" ", <<"dunia">>]]).
10
6> byte_size(iolist_to_binary([<<"halo">>, [" ", <<"dunia">>]])).
10

Fungsi iolist_to_binary/1 meratakan seluruh bersarang menjadi satu binary, sedangkan iolist_size/1 menghitung panjang totalnya tanpa meratakan. Padanan modern unicode:characters_to_binary/1 juga menerima iodata sekaligus menangani konversi unicode, sehingga dua kebutuhan itu selesai dalam satu panggilan:

erlang Menyatukan iodata lewat modul unicode
7> unicode:characters_to_binary([<<"ha">>, <<"lo">>]).
<<"halo">>

Konsekuensi desainnya penting: fungsi yang menerima iodata, seperti seluruh keluarga keluaran io dan pengiriman soket, dapat diberi potongan yang belum digabung, dan perakitan tunggal itu dilakukan di lapisan terbawah sekali saja.

Pola pembangunan binary dengan akumulator#

Pembangunan binary berulang mengikuti pola akumulator yang sama dengan list: potongan baru menempel di belakang akumulator lalu seluruhnya diratakan sekali. Pola <<Acc/binary, Potongan/binary>> menempelkan potongan baru ke akumulator pada tiap langkah, dan karena binary kecil murah disalin, pola ini aman untuk potongan berukuran wajar:

erlang Bentuk umum akumulator binary
gabung([]) -> <<>>;
gabung([K | S]) -> gabung_acc(S, K).

gabung_acc([], Acc) -> Acc;
gabung_acc([K | S], Acc) -> gabung_acc(S, <<Acc/binary, K/binary>>).

Fungsi pada contoh meniru iolist_to_binary/1 untuk list binary polos dan berhenti di kasus dasar list kosong. Sebagaimana idiom list terbalik, keputusan pentingnya ada di tempat perakitan terjadi: satu titik perakitan di akhir lebih murah daripada perakitan di setiap langkah, dan iodata membiarkan keputusan itu ditunda sampai memang diperlukan.

Iodata pada batas sistem#

Iodata bukan konvensi pustaka tertentu, melainkan kontrak seluruh lapisan keluaran Erlang: fungsi berkas menerima iodata, pengiriman soket menerima iodata, dan io menerima iodata, sehingga struktur bersarang yang dibangun proses bisnis dapat mengalir sampai ke disk atau jaringan tanpa perataan manual di tengah jalan. Pada lapisan terbawah, perataan dilakukan sekali oleh implementasinya, dan panjang totalnya selalu dapat ditanya dengan iolist_size/1 sebelum dikirim, kebiasaan yang berguna untuk menulis header panjang pada protokol: ukur dulu isi yang bersarang, tulis header yang menyatakan panjangnya, kirim keduanya sebagai satu iodata. Pola ini menjadikan iodata bukan sekadar penghematan, melainkan pola kerja membangun data yang bergerak dari banyak sumber menuju satu titik keluar.

Kesalahan umum#

  • Melupakan ukuran pada segmen hasil binary comprehension. Ekspresi hitungan di dalam <<>> wajib diberi ukuran eksplisit, dan error konstruksi binary adalah tanda ukurannya belum disebut.
  • Meratakan iodata secara manual sebelum mengirim. Pemanggilan iolist_to_binary/1 sebelum fungsi keluaran menggandakan pekerjaan, karena fungsi keluaran sudah menerima iodata apa adanya.
  • Menyambung binary besar berulang dengan <<Acc/binary, Baru/binary>> pada data raksasa. Setiap langkah menyalin akumulator. Kumpulan potongan yang besar sebaiknya dibiarkan bersarang sebagai iodata sampai titik perakitan tunggalnya.

Ringkasan#

  • Binary comprehension memakai generator <= dan menghasilkan binary, dengan ukuran segmen hasil yang wajib eksplisit.
  • Ukuran segmen menentukan pengemasan, dan nilai yang meluber dipotong tanpa error sebagaimana bit syntax biasa.
  • Iodata adalah struktur bersarang berisi binary dan list yang diterima fungsi keluaran tanpa perataan, dan iolist_size/1 mengukurnya tanpa meratakan.
  • Pembangunan binary berulang memakai akumulator dengan perakitan tunggal di akhir, sejajar dengan idiom list terbalik.

Referensi#