15. Mendapatkan input

Sejauh ini kamu menulis sendiri setiap nilai: mudah ditebak, tapi tidak interaktif. Bab ini membaca apa yang diketik pengguna di terminal.

Untuk ini Go butuh beberapa baris lebih banyak daripada untuk mencetak, dan tiga package tambahan. Bab ini membahasnya satu per satu.

Membaca satu baris

Ini program lengkapnya, dari exercises/15/01-read-name.go:

// Chapter 15 example: read a name and greet.
// Run with: go run exercises/15/01-read-name.go

package main

import (
    "bufio"
    "fmt"
    "os"
    "strings"
)

func main() {
    reader := bufio.NewReader(os.Stdin)

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

    fmt.Println("Hello, " + name)
}

Jalankan. Program mencetak pertanyaan, menunggu namamu dan Enter, mencetak sapaan, lalu selesai. Ada tiga baris yang melakukan pekerjaan baru:

  • reader := bufio.NewReader(os.Stdin) membuat variabel yang bisa membaca dari keyboard. os.Stdin ("standard input") adalah apa yang diketik pengguna di terminal, dan bufio adalah package yang membacanya dalam potongan yang praktis. Sebuah program butuh baris ini sekali, sebelum pembacaan pertama.
  • text, _ := reader.ReadString('\n') menunggu pengguna, lalu membaca semuanya sampai dan termasuk akhir baris. '\n' berarti "berhenti di baris baru". Tanda kutipnya tunggal karena ini satu karakter, bukan string. Seperti strconv.Atoi di Bab 14, fungsi ini mengembalikan dua nilai, dan _ membuang nilai kedua. Bab 21 menjelaskannya.
  • name := strings.TrimSpace(text) menghapus akhiran baris. Bagian berikutnya menjelaskan mengapa ini tidak boleh dilewati.

Buka exercises/15/01-read-name.go dan jalankan dua kali dengan nama yang berbeda. Perhatikan sapaannya berubah mengikuti nama itu.

Mengapa TrimSpace wajib

ReadString menyimpan akhiran baris sebagai bagian dari teks. Di Windows, menekan Enter menaruh dua karakter di akhir baris: \r dan \n. Jadi kalau kamu mengetik Keiko, text berisi tujuh byte, bukan lima.

Penanda %q mencetak string dengan tanda kutip di sekelilingnya dan karakter khususnya terlihat. exercises/15/05-line-ending.go memakainya untuk menunjukkan apa yang sebenarnya diterima. Di Windows, mengetik 7 lalu menekan Enter mencetak:

Type a number: 7
"7\r\n"
"7"
Without TrimSpace: 0
With TrimSpace: 7

strings.TrimSpace menghapus spasi, tab, dan akhiran baris dari kedua ujung string. Tanpa fungsi ini, dua hal menjadi salah:

  • Teks tercetak berantakan. fmt.Println("Hello, " + text + "!") menaruh ! di baris di bawah nama, karena akhiran barisnya ada di dalam text.
  • Angka menjadi 0. Bagi strconv.Atoi, "7\r\n" bukan angka, seperti yang ditunjukkan baris-baris terakhir output di atas.

Jadi setiap pembacaan di buku ini diikuti strings.TrimSpace.

Prompt di baris yang sama

fmt.Println pindah ke baris baru setelah pertanyaan, jadi pengguna mengetik di bawahnya. Untuk menjaga kursor di baris yang sama, gunakan fmt.Print, yang tidak menambahkan baris baru, dan akhiri prompt dengan spasi. Di dalam main, dengan import yang sama:

reader := bufio.NewReader(os.Stdin)

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

fmt.Println("Hello, " + name)

Output:

What is your name? Keiko
Hello, Keiko

Ini adalah exercises/15/02-prompt-same-line.go.

Membaca angka

ReadString selalu memberikan string, bahkan untuk digit. Untuk berhitung, rapikan dan konversi dengan strconv.Atoi dari Bab 14. Tambahkan "strconv" ke import:

reader := bufio.NewReader(os.Stdin)

fmt.Print("Enter a number: ")
text, _ := reader.ReadString('\n')
number, _ := strconv.Atoi(strings.TrimSpace(text))

fmt.Printf("Twice that is %d\n", number*2)

Baris konversi berisi dua panggilan sekaligus. Panggilan di dalam berjalan lebih dulu dan memberikan string yang sudah dirapikan; panggilan di luar mengubahnya menjadi int. Ini adalah exercises/15/03-read-number.go.

Untuk desimal, gunakan strconv.ParseFloat dengan cara yang sama:

reader := bufio.NewReader(os.Stdin)

fmt.Print("Enter a decimal: ")
text, _ := reader.ReadString('\n')
x, _ := strconv.ParseFloat(strings.TrimSpace(text), 64)

fmt.Printf("Twice that is %.2f\n", x*2)

Kalau pengguna mengetik sesuatu yang bukan bilangan bulat, seperti abc, 1.5, atau tidak mengetik apa-apa, strconv.Atoi memberikan 0. Program tidak crash dan tidak mencetak pesan; program berjalan terus dengan 0, seolah-olah pengguna mengetiknya. strconv.ParseFloat melakukan hal yang sama. Nilai kedua yang dibuang _ adalah satu-satunya yang melaporkan masalahnya. Kamu akan memeriksanya di Bab 21. Untuk sekarang, ketik angka saat program memintanya, dan kalau jawabannya salah, lihat apa yang kamu ketik. (Satu pengecualian: bilangan bulat yang terlalu besar untuk int memberikan int terbesar, bukan 0.)

Membaca beberapa nilai

Untuk membaca beberapa nilai, panggil ReadString sekali per nilai, selalu pada reader yang sama:

reader := bufio.NewReader(os.Stdin)

fmt.Print("First number:  ")
text, _ := reader.ReadString('\n')
a, _ := strconv.Atoi(strings.TrimSpace(text))

fmt.Print("Second number: ")
text, _ = reader.ReadString('\n')
b, _ := strconv.Atoi(strings.TrimSpace(text))

fmt.Printf("Sum: %d\n", a+b)

Setiap panggilan berhenti dan menunggu sendiri-sendiri. Program tidak lanjut ke baris berikutnya sampai Enter ditekan. Ini adalah exercises/15/04-read-two.go.

Perhatikan pembacaan kedua. text sudah ada, jadi baris itu memakai =, dan _ bukan variabel, jadi tidak dihitung sebagai baru. Menulis := di sana berhenti dengan no new variables on left side of :=. Di baris bawahnya, b, _ := boleh, karena b baru.

Kamu mengulang baris-baris ini untuk setiap nilai. Bab 21 menunjukkan cara memasukkannya ke dalam fungsi buatanmu sendiri dan menulisnya sekali saja.

PR

Starter PR hanya mengimpor fmt, dan komentar paling atasnya menunjukkan import yang kamu butuhkan. Ingat bahwa ekstensi Go untuk VS Code mungkin menambahkannya untukmu saat kamu menyimpan file.

Soal 1 — Sapa dengan nama

Buka exercises/15/homework/01-greet-by-name.go. Minta nama depan dengan fmt.Print, baca, rapikan, lalu cetak Hello, <name>!. Tanda seru adalah bagian dari output.

Soal 2 — Jumlah dua angka

Buka exercises/15/homework/02-sum-of-two.go. Minta dua angka (dengan prompt terpisah), konversi masing-masing dengan strconv.Atoi, lalu cetak jumlahnya seperti ini:

a + b = c

dengan a, b, c adalah nilai sebenarnya.

Soal 3 — Tahun menuju pensiun

Buka exercises/15/homework/03-retirement.go. Tanyakan umur pengguna dan hitung sisa tahun sampai umur 65. Cetak:

You have N years until retirement.

(Kalau seseorang berumur lebih dari 65, angkanya negatif. Tidak apa-apa — belum perlu menangani kasus itu.)

Tantangan — BMI

Buka exercises/15/homework/04-bmi.go. Minta tinggi dalam meter (desimal seperti 1.78) dan berat dalam kilogram (seperti 72.5). Gunakan strconv.ParseFloat untuk mengonversi keduanya. Hitung Indeks Massa Tubuh:

bmi := weight / (height * height)

Cetak hasilnya dengan satu angka desimal menggunakan fmt.Printf dengan %.1f. Beri label yang jelas.

Stuck atau sudah selesai? Buka halaman solusi PR.