リリース・改善中
Go ガイド · 2/6
この章は現在、英語でのみ提供しています。
Go keeps its grammar deliberately small. There are only a couple of dozen keywords, and there is usually one obvious way to write something. That makes Go code from different teams look remarkably alike. This chapter covers packages and imports, variables and constants, functions, control flow, and the distinctly Go-flavored defer.
Every Go file begins with a package clause. To use another package, import it and refer to its members through the package name. Visibility is decided by the first letter: identifiers starting with an uppercase letter (Println, Pi) are exported, and everything else stays private to its package.
package main
import (
"fmt"
"math"
"strings"
)
func main() {
fmt.Println(math.Pi)
fmt.Println(strings.ToUpper("go"))
}Importing a package and not using it is a compile error. It feels strict at first, but it means dead dependencies never pile up in your files.
Declare variables with var, or inside functions use the short form :=, which infers the type from the right-hand side. A variable declared without a value starts at its zero value: 0 for numbers, "" for strings, false for booleans, and nil for pointers, slices, maps, channels, functions, and interfaces. There is no such thing as an uninitialized variable in Go.
var count int // 0
var name = "gopher" // inferred as string
x, y := 10, 3.5 // int and float64
x, z := 20, true // allowed because z is new; x is just reassigned
const Limit = 100
const (
Read = 1 << iota // 1
Write // 2
Exec // 4
)iota counts up from zero within a const block, which makes it the idiomatic way to build enumerations and bit flags. Note that := only works inside functions; at package level you must use var. Declaring a local variable and never reading it is, again, a compile error.
Functions are declared with func, and types come after parameter names. The feature you will use constantly is multiple return values: Go functions conventionally return a result alongside an error rather than throwing.
func add(a, b int) int {
return a + b
}
// Return a value and an error together
func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, fmt.Errorf("cannot divide by zero")
}
return a / b, nil
}
// Named result plus a variadic parameter
func sum(nums ...int) (total int) {
for _, n := range nums {
total += n
}
return
}
func main() {
q, err := divide(10, 4)
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Println(q, sum(1, 2, 3))
double := func(n int) int { return n * 2 } // function literal (closure)
fmt.Println(double(add(1, 2)))
}Throw away results you do not need with the blank identifier _. Functions are first-class values, so you can store them in variables, pass them around, and build closures that capture surrounding variables.
Conditions take no parentheses, but braces are always required. There is exactly one loop keyword, for, and it covers what other languages split into for, while, and infinite loops.
// if can start with a short statement scoped to the if/else
if n, err := strconv.Atoi("42"); err == nil {
fmt.Println(n)
}
for i := 0; i < 3; i++ { // classic three-part loop
fmt.Println(i)
}
n := 1
for n < 100 { // behaves like while
n *= 2
}
for i, s := range []string{"a", "b"} { // iterate a slice
fmt.Println(i, s)
}
for i := range 3 { // range over an integer: 0, 1, 2
fmt.Println(i)
}
switch day := "sat"; day {
case "sat", "sun":
fmt.Println("weekend")
default:
fmt.Println("weekday")
}Each case in a switch ends on its own, so there is no break to forget. If you really want to fall into the next case, say so with fallthrough. A tagless switch { case x > 0: ... } is a tidy replacement for long if/else chains. Inside loops, break exits and continue skips to the next iteration.
defer schedules a call to run when the surrounding function returns, no matter which path it takes. That lets you put cleanup right next to the code that acquired the resource, so it is hard to forget. Multiple deferred calls run in last-in, first-out order.
func readFirstLine(path string) (string, error) {
f, err := os.Open(path)
if err != nil {
return "", err
}
defer f.Close() // runs on every return path
scanner := bufio.NewScanner(f)
if scanner.Scan() {
return scanner.Text(), nil
}
return "", scanner.Err()
}
func main() {
for i := 0; i < 3; i++ {
defer fmt.Println("deferred", i) // prints 2, 1, 0
}
}Arguments to a deferred call are evaluated immediately, when the defer statement runs, not when the call finally happens. One gotcha: deferring inside a loop keeps every resource open until the whole function returns. When you open files in a loop, move the loop body into its own function.
package, and only capitalized names are exported.:= inside functions; anything declared without a value gets its zero value.(result, error) is the standard shape.for is the only loop, and switch cases do not fall through by default.defer keeps cleanup next to acquisition and runs in reverse order.
コメント 0件
ログイン · ログインするとコメントできます。
最初のコメントを書いてみましょう。