16. if, else, dan switch

Sejauh ini, program selalu berjalan dengan cara yang sama setiap kali. Bab ini menambahkan kondisi: pertanyaan yang dijawab true atau false. Jawaban itu menentukan blok kode mana yang dijalankan. Seperti sebelumnya, contoh pendek hanya menampilkan baris yang masuk ke dalam main.

Membandingkan nilai

Kondisi dibangun dari operator perbandingan. Setiap operator membandingkan dua nilai dan memberikan sebuah bool.

Operator Arti
== sama dengan
!= tidak sama dengan
< kurang dari
> lebih dari
<= kurang dari atau sama dengan
>= lebih dari atau sama dengan
fmt.Println(7 == 7)     // true
fmt.Println(7 == 8)     // false
fmt.Println("a" == "A") // false (huruf besar-kecil berpengaruh)
fmt.Println(7 != 8)     // true
fmt.Println(3 < 5)      // true
fmt.Println(3 >= 3)     // true

Operator kesamaan adalah == (dua tanda sama dengan). Satu = adalah penugasan, yang mengubah variabel. Jadi if x = 7 { berhenti dengan:

syntax error: cannot use assignment x = 7 as value

Perbaikannya adalah if x == 7 {.

Pernyataan if

if menjalankan satu blok kode hanya ketika kondisinya benar.

age := 16
if age >= 18 {
    fmt.Println("You can vote.")
}

Baca dari kiri ke kanan: kalau umurnya setidaknya 18, cetak pesannya. Di sini age bernilai 16, jadi program tidak mencetak apa-apa.

Ada tiga aturan bentuknya:

  • Tidak ada tanda kurung di sekitar kondisi. Kamu boleh mengetiknya, dan Go menerimanya, tetapi ekstensi VS Code menghapusnya saat kamu menyimpan file (ekstensi itu menjalankan alat bernama gofmt).
  • Kurung kurawal wajib ada, bahkan untuk satu baris. Kalau dihilangkan, Go berhenti dengan syntax error: unexpected newline, expected { after if clause.
  • { pembuka berada di baris yang sama dengan if. Kamu sudah melihat alasannya di Bab 10: akhir baris bisa mengakhiri sebuah pernyataan. Kalau { berada di barisnya sendiri, muncul error yang sama.

Beri indentasi pada isi blok dengan tab. gofmt dan ekstensi VS Code melakukannya untukmu. Indentasi itu untuk manusia; kurung kurawal adalah yang memberi tahu Go di mana blok berakhir.

else untuk kasus lainnya

else berjalan ketika kondisinya salah. Bersama if, ia mencakup kedua kemungkinan tepat satu kali:

age := 16
if age >= 18 {
    fmt.Println("You can vote.")
} else {
    fmt.Println("Not old enough to vote yet.")
}

Output:

Not old enough to vote yet.

Tepat satu fmt.Println yang berjalan, tidak pernah keduanya.

else harus berada di baris yang sama dengan } penutup milik if. Menulisnya seperti ini terlihat masuk akal:

if age >= 18 {
    fmt.Println("You can vote.")
}
else {
    fmt.Println("Not old enough to vote yet.")
}

tetapi } di akhir barisnya menyelesaikan seluruh pernyataan if, sehingga Go lalu menemukan else yang tidak punya pasangan.

Buka exercises/16/02-else-on-new-line.go. File ini tidak bisa dikompilasi. Saat pertama dijalankan, ia mencetak:

# command-line-arguments
exercises\16\02-else-on-new-line.go:15:2: syntax error: unexpected else, expected }

Baris 15, kolom 2 adalah else. Pindahkan ke atas supaya barisnya menjadi } else {, lalu jalankan file itu lagi.

else if untuk rantai kondisi

Untuk lebih dari dua kasus, sambungkan dengan else if. Go mencoba setiap kondisi secara berurutan dan berhenti pada yang pertama bernilai benar:

score := 73
if score >= 90 {
    fmt.Println("Grade: A")
} else if score >= 80 {
    fmt.Println("Grade: B")
} else if score >= 70 {
    fmt.Println("Grade: C")
} else if score >= 60 {
    fmt.Println("Grade: D")
} else {
    fmt.Println("Grade: F")
}

Urutan itu penting: Go mengambil kecocokan pertama. Dengan score >= 60 di atas, setiap nilai lulus akan mendapat D, dan tidak ada yang melihat A, B, atau C.

Buka exercises/16/01-grade.go. Ubah score lalu jalankan. Coba nilai tepat di batas (60, 70, 80, 90) untuk memastikan >= menyertakannya.

Variabel yang dibuat di dalam blok

Variabel yang dideklarasikan dengan := di dalam blok hanya ada sampai } penutup blok itu. Kode ini terlihat baik-baik saja, tetapi tidak bisa dikompilasi:

score := 73
if score >= 60 {
    result := "pass"
} else {
    result := "fail"
}
fmt.Println(result)
result declared and not used
result declared and not used
undefined: result

Di sini ada dua variabel terpisah bernama result, satu di setiap blok, dan tidak ada yang dibaca. Di baris terakhir keduanya sudah hilang. Perbaikannya adalah mendeklarasikan variabel sebelum if, lalu memakai = biasa di dalam blok:

score := 73
var result string
if score >= 60 {
    result = "pass"
} else {
    result = "fail"
}
fmt.Println(result) // pass

var tanpa nilai, dari Bab 11, adalah cara yang biasa untuk menulis ini. Kamu akan sering memakai bentuk ini.

switch untuk satu nilai dan banyak kasus

Ketika sebuah rantai terus membandingkan nilai yang sama, switch menyatakannya dengan lebih rapi. Ini exercises/16/03-switch.go:

class := "Mage"

switch class {
case "Warrior":
    fmt.Println("Starts with a sword.")
case "Mage":
    fmt.Println("Starts with a staff.")
case "Rogue", "Thief":
    fmt.Println("Starts with a dagger.")
default:
    fmt.Println("Starts with nothing.")
}

Output:

Starts with a staff.

Go membandingkan class dengan setiap case dari atas ke bawah dan menjalankan yang pertama cocok. Beberapa hal yang perlu diketahui:

  • Sebuah case tidak berlanjut ke case berikutnya. Ketika barisnya selesai, seluruh switch selesai, dan Go lanjut ke kode sesudahnya. Kamu tidak perlu menulis apa pun untuk menghentikannya. (Go punya kata kunci fallthrough yang mengubah perilaku ini. Kamu jarang membutuhkannya, dan buku ini tidak memakainya.)
  • Satu case bisa mendaftar beberapa nilai, dipisahkan koma, seperti "Rogue", "Thief".
  • default berjalan ketika tidak ada case yang cocok. Bagian ini tidak wajib, dan ia adalah else milik switch.

Buka exercises/16/03-switch.go. Isi class dengan "Thief" lalu jalankan, kemudian dengan "Cook". Case mana yang berjalan setiap kali?

switch tanpa nilai

Tulis switch tanpa nilai, dan setiap case memegang kondisinya sendiri. Go menjalankan case pertama yang kondisinya benar. Ini keputusan yang sama dengan rantai if, dalam bentuk yang lebih rapi:

score := 73

switch {
case score >= 90:
    fmt.Println("Grade: A")
case score >= 80:
    fmt.Println("Grade: B")
case score >= 70:
    fmt.Println("Grade: C")
case score >= 60:
    fmt.Println("Grade: D")
default:
    fmt.Println("Grade: F")
}

Output:

Grade: C

Bandingkan dengan rantai else if tadi: urutannya sama, hasilnya sama. Pakai yang lebih enak dibaca. Kebanyakan programmer Go memilih switch ketika rantai punya lebih dari dua atau tiga cabang. Filenya adalah exercises/16/04-switch-no-value.go.

Kondisi hanya boleh ada di switch tanpa nilai. Kalau nilainya tetap ditulis, kode gagal, karena Go harus membandingkan int dengan bool:

score := 73
switch score {
case score >= 90:
    fmt.Println("Grade: A")
}
cannot convert score >= 90 (untyped bool value) to type int

Menggabungkan kondisi dengan &&, ||, !

Terkadang satu perbandingan saja tidak cukup. Go punya tiga operator logika yang menggabungkan bool:

Operator Arti
&& benar kalau kedua sisi benar
|| benar kalau salah satu sisi benar
! membalik benar menjadi salah dan salah menjadi benar
level := 12
hasKey := true

if level >= 10 && hasKey {
    fmt.Println("You can enter the dungeon.")
}

if level < 10 || !hasKey {
    fmt.Println("You are blocked.")
}

Output:

You can enter the dungeon.

Ini adalah exercises/16/05-and-or-not.go. Baca && sebagai "dan", || sebagai "atau", dan !hasKey sebagai "tidak punya kunci".

Mengambil keputusan dari teks

Bab 14 menyebut bahwa strings.Contains cocok dipasangkan dengan if. Karena ia memberikan bool, panggilan itu bisa menjadi seluruh kondisi:

message := "a dragon is sleeping in the cave"

if strings.Contains(message, "dragon") {
    fmt.Println("Be careful.")
} else {
    fmt.Println("All clear.")
}

Output:

Be careful.

Hal yang sama berlaku untuk strings.HasPrefix dan strings.HasSuffix:

command := "go north"
if strings.HasPrefix(command, "go ") {
    fmt.Println("You walk.")
}

Output:

You walk.

Untuk memeriksa apakah pengguna mengetik sesuatu, bandingkan dengan string kosong. Hanya bool yang boleh masuk ke if, aturan yang akan dibahas lebih dekat di Bab 17, jadi perbandingannya harus ditulis lengkap. Kalau pengguna menekan Enter tanpa mengetik nama:

reader := bufio.NewReader(os.Stdin)

fmt.Print("What is your name? ")
text, _ := reader.ReadString('\n')
name := strings.TrimSpace(text)

if name != "" {
    fmt.Println("Hello, " + name)
} else {
    fmt.Println("No name was entered.")
}

Output:

What is your name?
No name was entered.

Buka exercises/16/07-empty-answer.go dan jalankan dua kali: sekali dengan nama, dan sekali langsung menekan Enter. Lalu buka exercises/16/06-contains.go dan ubah kata di dalam message supaya cabang yang lain berjalan.

PR

Starter PR ada di exercises/16/homework/. Setiap starter bisa langsung dijalankan dan mencetak satu baris pengganti. Kalau soalnya membaca input, komentar paling atas starter menunjukkan import yang kamu butuhkan.

Soal 1 — Genap atau ganjil

Buka exercises/16/homework/01-even-or-odd.go. Minta sebuah angka. Cetak even atau odd berdasarkan apakah n % 2 bernilai 0.

Soal 2 — Gerbang level

Buka exercises/16/homework/02-level-gate.go. Ada dua variabel di bagian atas: level (angka) dan hasKey (bool). Cetak You can enter the dungeon. hanya kalau pemain setidaknya level 10 dan punya kunci. Kalau tidak, cetak salah satu dari:

  • Level too low. (kalau hanya levelnya yang bermasalah),
  • Missing the key. (kalau levelnya cukup tetapi kuncinya tidak ada),
  • Level too low and missing the key. (kalau keduanya salah).

Soal 3 — Huruf nilai

Buka exercises/16/homework/03-grade-letter.go. Minta nilai (0 sampai 100). Cetak huruf nilai A, B, C, D, atau F dengan batas yang sama seperti contoh di bab ini. Gunakan switch tanpa nilai.

Tantangan — Terbesar dari tiga

Buka exercises/16/homework/04-largest-of-three.go. Tiga variabel berisi tiga angka. Cetak yang terbesar, dengan if dan operator perbandingan. Go punya max bawaan, tetapi jangan memakainya di sini; menyusun perbandingannya itulah intinya. Tambahannya: tangani nilai seri dengan rapi (kalau dua angka sama-sama terbesar, cetak nilai itu sekali).

Stuck atau sudah selesai? Buka halaman solusi PR.