List, Dict, dan iterasi

Menggunakan List dan Dict yang dapat tumbuh beserta perulangan for-in dan mutasi elemen lewat ref.

Daftar isi

List dan Dict pada pustaka standar Mojo adalah dua kontainer dinamis yang ukurannya dapat berubah selama program berjalan. Topik ini membahas pembuatan List dan Dict dari literal, penambahan serta pengambilan elemen, perulangan for-in untuk membaca elemen, mutasi elemen lewat referensi ref, dan aturan raises yang menyertai akses kunci Dict. Setelah topik ini dibaca, koleksi yang dapat tumbuh dapat digunakan dengan mengetahui mekanisme penyimpanan dan batasan yang menyertainya.

List: kontainer yang dapat tumbuh#

List adalah kontainer berurutan yang elemennya bertipe sama dan jumlahnya ditentukan saat program berjalan, bukan saat kompilasi. Tipe List ditulis List[T] dengan T sebagai tipe elemennya, misalnya List[Int] untuk deret bilangan bulat. Elemen paling mudah diisi melalui literal, yaitu notasi nilai yang ditulis langsung seperti [28, 30, 32]. Literal tersebut menjadi List ketika anotasi tipenya menyebutkan List, sehingga deklarasi var suhu: List[Int] = [28, 30, 32] menghasilkan List berisi tiga elemen.

Metode append menambahkan elemen di akhir, sedangkan pop mengambil elemen terakhir sekaligus mengeluarkannya dari List. Fungsi len menghitung jumlah elemen, dan akses satu elemen menggunakan indeks dalam kurung siku dengan penomoran mulai dari nol. Konstruktor variadic era pra-1.0 seperti List[Int](1, 2, 3) telah dihapus sejak rilis 1.0, sehingga literal dan append menjadi cara baku mengisi List. Perulangan for x in suhu membaca setiap elemen dari awal ke akhir tanpa indeks manual.

Berkas daftar.mojo memperagakan seluruh operasi tersebut pada catatan suhu harian.

mojo daftar.mojo
def main():
    var suhu: List[Int] = [28, 30, 32]
    print(suhu)
    suhu.append(31)
    print(suhu)
    print(len(suhu))
    print(suhu[0])

    var terakhir = suhu.pop()
    print(terakhir)
    print(len(suhu))
    for x in suhu:
        print(x)
bash
# jalankan program List dari literal sampai perulangan
mojo run daftar.mojo
text Keluaran
[28, 30, 32]
[28, 30, 32, 31]
4
28
31
3
28
30
32

Keluaran [28, 30, 32, 31] menunjukkan elemen hasil append, sedangkan 31 berikutnya adalah nilai kembalian pop, dan 3 adalah panjang List setelah pengambilan itu. print pada List menampilkannya dengan bentuk serupa Python, yaitu elemen dipisahkan koma dan diapit tanda kurung siku. Nilai 28 berasal dari indeks suhu[0], dan tiga baris terakhir adalah hasil perulangan for-in setelah satu elemen terakhir dikeluarkan.

Mutasi elemen lewat ref#

Perulangan for-in pada List memberikan setiap elemen sebagai peminjaman yang tak dapat diubah, sesuai konvensi argumen bawaan Mojo. Akibatnya, penugasan pada variabel perulangan biasa ditolak compiler. Untuk mengubah elemen List dari dalam perulangan, gunakan bentuk for ref item in bacaan. Kata kunci ref menjadikan variabel perulangan referensi yang dapat diubah, sehingga penugasan lewat referensi tersebut menulis langsung ke penyimpanan List aslinya.

Berkas mutasi-elemen.mojo mengalikan setiap bacaan sensor dengan sepuluh melalui perulangan berbasis ref.

mojo mutasi-elemen.mojo
def main():
    var bacaan: List[Int] = [12, 30, 45]
    for ref item in bacaan:
        item = item * 10
    print(bacaan)
bash
# mutasi elemen lewat referensi ref
mojo run mutasi-elemen.mojo
text Keluaran
[120, 300, 450]

Keluaran [120, 300, 450] menunjukkan seluruh elemen berubah dalam satu perulangan tanpa indeks manual. Kata kunci ref menempatkan mutasi pada penyimpanan List, bukan pada salinan lokal, sehingga List asli benar-benar terubah. Niat mutasi juga terbaca langsung dari sintaksnya, sehingga perulangan biasa tetap dapat diasumsikan hanya membaca.

Dict: pemetaan kunci ke nilai#

Dict adalah pemetaan (mapping) dari kunci ke nilai, ditulis Dict[K, V] dengan K sebagai tipe kunci dan V sebagai tipe nilai. Deklarasinya menggunakan literal kurung kurawal seperti {"matematika": 85.0}. Akses satu nilai lewat nilai["matematika"] dapat gagal apabila kuncinya tidak ada, sehingga pemanggilan tersebut dikategorikan sebagai operasi yang dapat melempar error dan wajib berada di konteks raises. Deklarasi def main() raises pada berkas contoh hadir karena aturan ini.

Kunci baru ditambahkan lewat penugasan nilai["kimia"] = 90.0, dan keberadaan kunci diperiksa dengan operator in. Metode items() mengembalikan seluruh entri untuk diperulangkan, dan setiap entri menyediakan key beserta value. Fungsi len menghitung jumlah entri pada Dict.

mojo kamus.mojo
def main() raises:
    var nilai: Dict[String, Float64] = {"matematika": 85.0, "fisika": 78.5}
    print(len(nilai))
    print(nilai["matematika"])
    nilai["kimia"] = 90.0
    print("kimia" in nilai)
    for item in nilai.items():
        print(item.key, item.value)
bash
# jalankan program Dict beserta iterasi items
mojo run kamus.mojo
text Keluaran
2
85.0
True
matematika 85.0
fisika 78.5
kimia 90.0

Keluaran menampilkan panjang awal 2, nilai 85.0 dari kunci matematika, dan True setelah kunci kimia ditambahkan. Tiga baris terakhir adalah pasangan kunci dan nilai dari items(), termasuk entri yang baru saja ditambahkan. Pola perulangan atas items() menjadi cara baku membaca seluruh isi Dict tanpa menuliskan kuncinya satu per satu.

Kesalahan umum#

Kesalahan pertama adalah menugaskan nilai pada variabel perulangan biasa dengan maksud mengubah elemen. Variabel tersebut hanyalah peminjaman yang tak dapat diubah, sehingga compiler menolak penugasannya. Berkas mutasi-gagal.mojo memuat penugasan semacam itu.

mojo mutasi-gagal.mojo
def main():
    var bacaan: List[Int] = [12, 30, 45]
    for x in bacaan:
        x = x * 10
    print(bacaan)
bash
# penugasan pada variabel perulangan biasa ditolak compiler
mojo run mutasi-gagal.mojo
text Keluaran
/home/kal/my-project/content/mojo/koleksi-dan-string/list-dict-iterasi/mutasi-gagal.mojo:4:9: error: expression must be mutable in assignment
        x = x * 10
        ^
/home/kal/.pixi/envs/mojo/bin/mojo: error: failed to parse the provided Mojo source module

Pesan expression must be mutable in assignment menyatakan bahwa x bukan penyimpanan yang dapat ditulis. Perbaikannya adalah mengganti bentuk perulangannya menjadi for ref x in bacaan sebagaimana diperagakan pada berkas mutasi-elemen.mojo. Dengan ref, penugasan menulis ke elemen List aslinya dan program berjalan sesuai harapan.

Kesalahan kedua adalah mengakses kunci Dict di dalam fungsi tanpa raises. Akses kunci dikategorikan sebagai operasi yang dapat melempar error karena kuncinya mungkin tidak ada. Berkas akses-raises.mojo memuat akses semacam itu di dalam def main() biasa.

mojo akses-raises.mojo
def main():
    var nilai: Dict[String, Float64] = {"matematika": 85.0}
    print(nilai["matematika"])
bash
# akses kunci di konteks tanpa raises ditolak compiler
mojo run akses-raises.mojo
text Keluaran
/home/kal/my-project/content/mojo/koleksi-dan-string/list-dict-iterasi/akses-raises.mojo:3:16: error: cannot call function that may raise in a context that cannot raise
    print(nilai["matematika"])
          ~~~~~^~~~~~~~~~~~~~
/home/kal/my-project/content/mojo/koleksi-dan-string/list-dict-iterasi/akses-raises.mojo:3:16: note: try surrounding the call in a 'try' block
    print(nilai["matematika"])
               ^
/home/kal/my-project/content/mojo/koleksi-dan-string/list-dict-iterasi/akses-raises.mojo:1:5: note: or mark surrounding function as 'raises'
def main():
    ^
/home/kal/.pixi/envs/mojo/bin/mojo: error: failed to parse the provided Mojo source module

Pesan error menawarkan dua jalan perbaikan, yaitu membungkus pemanggilan dalam blok try atau menandai fungsi penampungnya dengan raises. Contoh pada bagian Dict memilih opsi kedua dengan def main() raises. Kedua opsi membuat penanganan kegagalan eksplisit, bukan tersembunyi di balik perilaku diam-diam.

Kesalahan ketiga adalah membaca kunci yang memang tidak ada. Compiler tidak lagi menolaknya karena konteksnya sudah raises, tetapi error muncul saat program berjalan. Berkas kunci-hilang.mojo membaca kunci fisika pada Dict yang hanya berisi matematika.

mojo kunci-hilang.mojo
def main() raises:
    var nilai: Dict[String, Float64] = {"matematika": 85.0}
    print(nilai["fisika"])
bash
# kunci yang tidak ada melempar error saat program berjalan
mojo run kunci-hilang.mojo
text Keluaran
stack trace was not collected. Enable stack trace collection with environment variable `MODULAR_DEBUG=stack-trace-on-error`
Unhandled exception caught during execution: DictKeyError[String]()
/home/kal/.pixi/envs/mojo/bin/mojo: error: execution exited with a non-zero result: 1

Exception DictKeyError[String], yaitu error yang dilemparkan saat program berjalan, menghentikan program karena tidak ada penanganan yang menyertai pemanggilan itu. Perbaikannya adalah memeriksa keberadaan kunci dengan operator in sebelum mengaksesnya, atau membungkus aksesnya dalam blok try dengan penanganan sesuai. Kedua cara menjaga program tetap berjalan ketika data masukannya belum tentu lengkap.

Ringkasan#

  • List[T] adalah kontainer dinamis yang diisi lewat literal beranotasi atau append, dibaca lewat indeks dan for-in, serta dikurangi lewat pop, dengan len menghitung elemennya.
  • Mutasi elemen dalam perulangan memerlukan for ref item in l, karena variabel perulangan biasa hanyalah peminjaman yang tak dapat diubah.
  • Dict[K, V] memetakan kunci ke nilai, akses kuncinya dapat melempar error sehingga wajib berada di konteks raises, dan seluruh entrinya diperulangkan lewat items().
  • Konstruktor variadic List[Int](1, 2, 3) telah dihapus sejak rilis 1.0, dan literal tanpa anotasi tipe diinferensikan menjadi Array, bukan List.

Referensi#