21. Fungsi dan error — Solusi PR

File solusi .go ada di exercises/21/homework/solutions/.

Soal 1 — Sapa

Soal. Fungsi greet yang mencetak sapaan, dipanggil tiga kali.

Cara berpikir. Satu parameter, satu baris cetak. Fungsinya berada di luar main, dan main memberikan string pada setiap panggilan.

Solusi yang dikerjakan.

package main

import "fmt"

func greet(name string) {
    fmt.Printf("Hello, %s!\n", name)
}

func main() {
    greet("Keiko")
    greet("Arif")
    greet("World")
}

Output:

Hello, Keiko!
Hello, Arif!
Hello, World!

Kesalahan umum.

  • Menulis return dan tipe kembalian padahal fungsinya harus mencetak. Fungsi ini langsung mencetak, dan pemanggil tidak butuh nilai kembalian.
  • Tidak menulis tipe parameter, seperti func greet(name) {. Go membaca name sebagai tipe yang belum pernah didengarnya, dan berhenti dengan undefined: name.

Soal 2 — isEven

Soal. Kembalikan true atau false dari n%2 == 0. Tidak ada pencetakan di dalam fungsi.

Cara berpikir. n%2 == 0 sudah berupa bool. Langsung return, dan biarkan pemanggil yang mencetaknya.

Solusi yang dikerjakan.

package main

import "fmt"

func isEven(n int) bool {
    return n%2 == 0
}

func main() {
    fmt.Println(isEven(4))  // true
    fmt.Println(isEven(7))  // false
    fmt.Println(isEven(0))  // true
    fmt.Println(isEven(-2)) // true
}

Satu baris itu adalah seluruh isi fungsinya: Go menghitung n%2, membandingkannya dengan 0, lalu mengembalikan bool-nya.

Kesalahan umum.

  • Menulis fungsinya seperti ini:
func isEven(n int) bool {
    if n%2 == 0 {
        return true
    } else {
        return false
    }
}

Lima baris untuk hal yang dikerjakan satu baris di atas. n%2 == 0 sudah berupa bool.

Soal 3 — Clamp

Soal. clamp mengembalikan x, dijaga tetap di dalam rentang dari lo sampai hi.

Cara berpikir. Dua pemeriksaan penjaga di atas menangani kasus di luar rentang. Selain itu, kembalikan x tanpa diubah.

Solusi yang dikerjakan.

package main

import "fmt"

func clamp(x int, lo int, hi int) int {
    if x < lo {
        return lo
    }
    if x > hi {
        return hi
    }
    return x
}

func main() {
    fmt.Println(clamp(5, 0, 10))  // 5
    fmt.Println(clamp(-3, 0, 10)) // 0
    fmt.Println(clamp(99, 0, 10)) // 10
}

Kedua blok if berdiri sendiri karena masing-masing melakukan return: yang pertama berjalan mengakhiri fungsi. Kalau tidak ada, return x yang berjalan.

Kesalahan umum.

  • Mengira clamp(99, 0, 10) menghasilkan 99. Hasilnya dipaksa masuk ke dalam rentang, jadi nilainya 10.

Tantangan — Persen

Soal. Fungsi yang mengembalikan angka dan error, dengan dua cara untuk gagal, dan pemanggil yang memeriksa error-nya.

Cara berpikir. Ada tiga hasil, jadi ada tiga baris return. Periksa teks yang salah lebih dulu, karena pemeriksaan rentang membutuhkan angka yang sungguhan. Kalau berhasil, error-nya nil. Kalau gagal, angkanya tidak penting, jadi kembalikan 0.

Solusi yang dikerjakan.

package main

import (
    "errors"
    "fmt"
    "strconv"
)

func parsePercent(text string) (int, error) {
    number, err := strconv.Atoi(text)
    if err != nil {
        return 0, err
    }
    if number < 0 || number > 100 {
        return 0, errors.New("percent must be 0 to 100")
    }
    return number, nil
}

func report(text string) {
    percent, err := parsePercent(text)
    if err != nil {
        fmt.Println("Error:", err)
        return
    }
    fmt.Println("Percent:", percent)
}

func main() {
    report("85")
    report("abc")
    report("150")
}

Output:

Percent: 85
Error: strconv.Atoi: parsing "abc": invalid syntax
Error: percent must be 0 to 100

Error pertama berasal dari strconv.Atoi, dan parsePercent hanya meneruskannya. Error kedua buatanmu sendiri. report menangani keduanya dengan cara yang sama, karena bagi pemanggil keduanya hanyalah sebuah error.

Kesalahan umum.

  • Memakai number sebelum memeriksa err. Kalau err bukan nil, number bernilai 0, yang terlihat seperti persen yang sah.
  • Menulis percent := parsePercent(text). Fungsinya memberikan dua nilai, jadi Go berhenti dengan assignment mismatch: 1 variable but parsePercent returns 2 values.
  • Mencetak error di dalam parsePercent. Kembalikan error-nya, dan biarkan pemanggil yang memutuskan apa yang harus dilakukan.

Selesai?

Dua bab berikutnya membahas slice dan map, cara bawaan Go untuk menampung banyak nilai. Lalu package untuk memecah kode ke beberapa file, dan mini-proyek Bagian 5: petualangan teks.