2013-11-23 wcdj
0 摘要
本文通过对A Tour of Go的实践,总结Go语言的基础用法。
1 Go语言”奇怪用法“有哪些?
1,go的变量声明顺序是:”先写变量名,再写类型名“,此与C/C++的语法孰优孰劣,可见下文解释:
http://blog.golang.org/gos-declaration-syntax
2,go是通过package来组织的(与python类似),只有package名为main的包可以包含main函数,一个可执行程序有且仅有一个main包,通过import关键字来导入其他非main包。
3,可见性规则。go语言中,使用大小写来决定该常量、变量、类型、接口、结构或函数是否可以被外部包含调用。根据约定,函数名首字母小写即为private,函数名首字母大写即为public。
4,go内置关键字(25个均为小写)。
5,函数不用先声明,即可使用。
6,在函数内部可以通过 := 隐士定义变量。(函数外必须显示使用var定义变量)
7,go程序使用UTF-8编码的纯Unicode文本编写。
8,使用big.Int的陷阱:
http://stackoverflow.com/questions/11270547/go-big-int-factorial-with-recursion
9,从技术层面讲,go语言的语句是以分号分隔的,但这些是由编译器自动添加的,不用手动输入,除非需要在同一行中写入多个语句。没有分号及只需少量的逗号和圆括号,使得go语言的程序更容易阅读。
10,go语言只有一个循环结构——for循环。
11,go里的自增运算符只有——“后++”
12,go语言中的slice用法类似python中数组,关于slice的详细用法可见:http://blog.golang.org/go-slices-usage-and-internals
13,函数也是一个值,使用匿名函数返回一个值。
14,函数闭包的使用,闭包是一个匿名函数值,会引用到其外部的变量。
2 代码实践
/* gerryyang * 2013-11-23 */ package main import ( "fmt" "math" "math/big" "math/cmplx" "math/rand" "net/http" "os" "runtime" "time" ) // Outside a function, every construct begins with a keyword (var, func, and so on) and the := construct is not available // The var statement declares a list of variables; as in function argument lists, the type is last var x, y, z int var c, python, java bool // A var declaration can include initializers, one per variable var x1, y1, z1 int = 1, 2, 3 // If an initializer is present, the type can be omitted; the variable will take the type of the initializer var c1, python1, java1 = true, false, "no!" // basic types // bool // string // int int8 int16 int32 int64 // uint uint8 uint16 uint32 uint64 uintptr // byte (alias for uint8) // rune (alias for int32, represents a Unicode code point) // float32 float64 // complex64 complex128 var ( ToBe bool = false MaxInt uint64 = 1<<64 - 1 complex complex128 = cmplx.Sqrt(-5 + 12i) ) // Constants are declared like variables, but with the const keyword const Pi = 3.14 // Constants can be character, string, boolean, or numeric values const World = "世界" // Numeric Constants const ( Big = 1 << 100 Small = Big >> 99 // 2 ) type Vertex struct { X int Y int } type Vertex2 struct { Lat, Long float64 } var m map[string]Vertex2 // Map literals are like struct literals, but the keys are required var m2 = map[string]Vertex2{ "gerryyang": Vertex2{ 100, 200, }, "wcdj": Vertex2{ -300, 500, }, } // If the top-level type is just a type name, you can omit it from the elements of the literal var m3 = map[string]Vertex2{ "math": {20, 40}, "computer": {30, 50}, } type Vertex3 struct { X, Y float64 } type MyFloat float64 type Abser interface { Abs() float64 } //////////////////////////////////////////////////////// func main() { fmt.Println("Hello Golang, I'm gerryyang") fmt.Println("The time is", time.Now()) // To see a different number, seed the number generator; see rand.Seed fmt.Println("My favorite number is", rand.Intn(7)) fmt.Printf("Now you have %g problesms\n", math.Nextafter(2, 3)) // In Go, a name is exported if it begins with a capital letter fmt.Println(math.Pi) // Notice that the type comes after the variable name fmt.Println(add(42, 13)) fmt.Println(add2(42, 13)) // multiple results a, b := swap("gerry", "yang") fmt.Println(a, b) // named return fmt.Println(split(17)) fmt.Println(split2(17)) // var used fmt.Println(x, y, z, c, python, java) fmt.Println(x1, y1, z1, c1, python1, java1) // Inside a function, the := short assignment statement can be used in place of a var declaration with implicit type var x2, y2, z2 int = 1, 2, 3 c2, python2, java2 := true, false, "yes!" fmt.Println(x2, y2, z2, c2, python2, java2) // basic types const f = "%T(%v)\n" fmt.Printf(f, ToBe, ToBe) fmt.Printf(f, MaxInt, MaxInt) fmt.Printf(f, complex, complex) // Constants cannot be declared using the := syntax const World2 = "和平" const Truth = true fmt.Println(Pi) fmt.Println("你好", World) fmt.Println("世界", World2) fmt.Println("Go rules?", Truth) // Numeric Constants fmt.Println(needInt(Small)) ////fmt.Println(needInt(Big))// error, constant 1267650600228229401496703205376 overflows int ////fmt.Println(needInt64(Big)) // error, same as above ////fmt.Println(needBigInt(big.NewInt(Big)))// error, 使用big.Int貌似入参最大类型只支持int64 fmt.Println(needFloat(Small)) fmt.Println(needFloat(Big)) // Go has only one looping construct, the for loop // The basic for loop looks as it does in C or Java, except that the ( ) are gone (they are not even optional) and the { } are required sum := 0 for i := 0; i < 10; i++ { sum += i } fmt.Println(sum) // As in C or Java, you can leave the pre and post statements empty // At that point you can drop the semicolons: C's while is spelled for in Go sum1 := 1 for sum1 < 1000 { sum1 += sum1 } fmt.Println(sum1) // If you omit the loop condition it loops forever, so an infinite loop is compactly expressed ivar := 1 for { if ivar++; ivar > 1000 { fmt.Println("leave out an infinite loop") break } } // The if statement looks as it does in C or Java, except that the ( ) are gone and the { } are required fmt.Println(sqrt(2), sqrt(-4)) // Like for, the if statement can start with a short statement to execute before the condition fmt.Println(pow(3, 2, 10), pow(3, 3, 20)) // If and else fmt.Println(pow2(3, 2, 10), pow2(3, 3, 20)) //////////////////////////////////////////////////////////// // A struct is a collection of fields fmt.Println(Vertex{1, 2}) // Struct fields are accessed using a dot v := Vertex{1, 2} v.X = 4 fmt.Println(v) // Go has pointers, but no pointer arithmetic // Struct fields can be accessed through a struct pointer. The indirection through the pointer is transparent p := Vertex{1, 2} q := &p q.X = 1e9 fmt.Println(p) // struct literals // A struct literal denotes a newly allocated struct value by listing the values of its fields p = Vertex{1, 2} // has type Vertex q = &Vertex{1, 2} // has type * Vertex r := Vertex{X: 1} // Y:0 is implicit s := Vertex{} // X:0 and Y:0 fmt.Println(p, q, r, s) // The expression new(T) allocates a zeroed T value and returns a pointer to it // var t *T = new(T) or t := new(T) pv := new(Vertex) fmt.Println(pv) pv.X, pv.Y = 11, 9 fmt.Println(pv) // A slice points to an array of values and also includes a length // []T is a slice with elements of type T as := []int{2, 3, 5, 7, 11, 13} fmt.Println("as ==", as) for i := 0; i < len(as); i++ { fmt.Printf("as[%d] == %d\n", i, as[i]) } // Slices can be re-sliced, creating a new slice value that points to the same array // The expression: s[lo:hi] // evaluates to a slice of the elements from lo through hi-1, inclusive fmt.Println("as[1:4] ==", as[1:4]) // missing low index implies 0 fmt.Println("as[:3] ==", as[:3]) // missing high index implies len(s) fmt.Println("as[4:] ==", as[4:]) // Slices are created with the make function. It works by allocating a zeroed array and returning a slice that refers to that array // a := make([]int, 5), note, len(a) = 5 // To specify a capacity, pass a third argument to make // b := make([]int, 0 , 5), note, len(b) = 0, cap(b) = 5 // b = b[:cap(b)], note, len(b) = 5, cap(b) = 5 // b = b[1:], note, len(b) = 4, cap(b) = 4 s1 := make([]int, 5) printSlice("s1", s1) s2 := make([]int, 0, 5) printSlice("s2", s2) s3 := s2[:2] printSlice("s3", s3) s4 := s3[2:5] printSlice("s4", s4) // The zero value of a slice is nil // A nil slice has a length and capacity of 0 var s5 []int fmt.Println(s5, len(s5), cap(s5)) if s5 == nil { fmt.Println("slice is nil") } // The range form of the for loop iterates over a slice or map var s6 = []int{1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024} for i, v := range s6 { fmt.Printf("2**%d = %d\n", i, v) } // If you only want the index, drop the ", value" entirely for i := range s6 { s6[i] = 1 << uint(i) } // You can skip the index or value by assigning to _ for _, value := range s6 { fmt.Printf("%d\n", value) } // A map maps keys to values // Maps must be created with make (not new) before use; the nil map is empty and cannot be assigned to m = make(map[string]Vertex2) m["Bell Labs"] = Vertex2{ 40.68433, -74.39967, } fmt.Println(m["Bell Labs"]) // Map literals are like struct literals, but the keys are required fmt.Println(m2) // If the top-level type is just a type name, you can omit it from the elements of the literal fmt.Println(m3) // map // insert, update, retrieve, delete, test m4 := make(map[string]int) m4["date"] = 20131129 fmt.Println("The value:", m4["date"]) m4["date"] = m4["date"] + 1 fmt.Println("The value:", m4["date"]) date, ok := m4["date"] fmt.Println("The value:", date, "Present?", ok) delete(m4, "date") fmt.Println("The value:", m4["date"]) date2, ok := m4["date"] fmt.Println("The value:", date2, "Present?", ok) // Function values // Functions are values too hypot := func(x, y float64) float64 { return math.Sqrt(x*x + y*y) } fmt.Println(hypot(3, 4)) // Function closures // For example, the adder function returns a closure. Each closure is bound to its own sum variable pos, neg := adder(), adder() for i := 0; i < 10; i++ { fmt.Println(pos(i), neg(-2*i)) } // fibonacci fib := fibonacci() for i := 0; i < 10; i++ { fmt.Println(fib()) } // switch // A case body breaks automatically, unless it ends with a fallthrough statement switch os := runtime.GOOS; os { case "darwin": fmt.Println("OS X") case "linux": fmt.Println("Linux") default: // freebsd, openbsd // plan9, windows... fmt.Printf("%s", os) } // Switch cases evaluate cases from top to bottom, stopping when a case succeeds // Note: Time in the Go playground always appears to start at 2009-11-10 23:00:00 UTC fmt.Println("When's Saturday?") today := time.Now().Weekday() switch time.Saturday { case today + 0: fmt.Println("Today") case today + 1: fmt.Println("Tomorrow") case today + 2: fmt.Println("In two days") case today + 3: fmt.Println("In three days") default: fmt.Println("Too far away") } // Switch without a condition is the same as switch true // This construct can be a clean way to write long if-then-else chains t_now := time.Now() switch { case t_now.Hour() < 12: fmt.Println("Good morning!") case t_now.Hour() < 17: fmt.Println("Good afternoon") default: fmt.Println("Good evening") } // Go does not have classes. However, you can define methods on struct types v3 := &Vertex3{3, 4} fmt.Println(v3.Abs()) // In fact, you can define a method on any type you define in your package, not just structs // You cannot define a method on a type from another package, or on a basic type f1 := MyFloat(-math.Sqrt2) fmt.Println(f1.Abs()) // Methods with pointer receivers // Methods can be associated with a named type or a pointer to a named type // We just saw two Abs methods. One on the *Vertex pointer type and the other on the MyFloat value type // There are two reasons to use a pointer receiver. First, to avoid copying the value on each method call (more efficient if the value type is a large struct). Second, so that the method can modify the value that its receiver points to v3 = &Vertex3{3, 4} v3.Scale(5) fmt.Println(v3, v3.Abs()) // An interface type is defined by a set of methods // A value of interface type can hold any value that implements those methods var a_interface Abser v4 := Vertex3{3, 4} a_interface = f1 // a MyFloat implements Abser a_interface = &v4 // a *Vertex3 implements Abser //a_interface = v4 // a Vertex3, does Not, error! fmt.Println(a_interface.Abs()) // Interfaces are satisfied implicitly var w Writer // os.Stdout implements Writer w = os.Stdout fmt.Fprintf(w, "hello, writer\n") // An error is anything that can describe itself as an error string. The idea is captured by the predefined, built-in interface type, error, with its single method, Error, returning a string: type error interface { Error() string } if err := run(); err != nil { fmt.Println(err) } // Web servers //var h Hello //http.ListenAndServe("localhost:4000", h) } ///////////////////////////////////////////// // func can be used before declare func add(x int, y int) int { return x + y } // When two or more consecutive named function parameters share a type, you can omit the type from all but the last func add2(x, y int) int { return x + y } // multiple results, a function can return any number of results func swap(x, y string) (string, string) { return y, x } // In Go, functions can return multiple "result parameters", not just a single value. They can be named and act just like variables func split(sum int) (x, y int) { x = sum * 4 / 9 y = sum - x return y, x } // In Go, functions can return multiple "result parameters", not just a single value. They can be named and act just like variables func split2(sum int) (x, y int) { x = sum * 4 / 9 y = sum - x // If the result parameters are named, a return statement without arguments returns the current values of the results return } func needInt(x int) int { return x*10 + 1 } func needInt64(x int64) int64 { return x*10 + 1 } func needBigInt(x *big.Int) (result *big.Int) { result = new(big.Int) result.Set(x) result.Mul(result, big.NewInt(10)) return } func needFloat(x float64) float64 { return x * 0.1 } func sqrt(x float64) string { if x < 0 { return sqrt(-x) + "i" } return fmt.Sprint(math.Sqrt(x)) } // Variables declared by the statement are only in scope until the end of the if func pow(x, n, lim float64) float64 { if v := math.Pow(x, n); v < lim { return v } return lim } // Variables declared inside an if short statement are also available inside any of the else blocks func pow2(x, n, lim float64) float64 { if v := math.Pow(x, n); v < lim { return v } else { fmt.Printf("%g >= %g\n", v, lim) } // can't use v here, though return lim } func printSlice(s string, x []int) { fmt.Printf("%s len = %d cap = %d %v\n", s, len(x), cap(x), x) } // Go functions may be closures. A closure is a function value that references variables from outside its body. The function may access and assign to the referenced variables; in this sense the function is "bound" to the variables func adder() func(int) int { sum := 0 return func(x int) int { sum += x return sum } } // fibonacci is a function that returns // a function that returns an int. func fibonacci() func() int { p := 0 q := 1 s := 0 return func() int { s = p + q p = q q = s return s } } // The method receiver appears in its own argument list between the func keyword and the method name func (v *Vertex3) Abs() float64 { return math.Sqrt(v.X*v.X + v.Y*v.Y) } func (f MyFloat) Abs() float64 { if f < 0 { fmt.Println("f < 0 here") return float64(-f) } return float64(f) } // Methods with pointer receivers func (v *Vertex3) Scale(f float64) { v.X = v.X * f v.Y = v.Y * f } // Interfaces are satisfied implicitly type Reader interface { Read(b []byte) (n int, err error) } type Writer interface { Write(b []byte) (n int, err error) } type ReadWriter interface { Reader Writer } // error control type MyError struct { When time.Time What string } func (e *MyError) Error() string { return fmt.Sprintf("at %v, %s", e.When, e.What) } func run() error { return &MyError{ time.Now(), "it didn't work", } } // Web servers type Hello struct{} func (h Hello) ServeHTTP( w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, "gerryyang") } /* output: Hello Golang, I'm gerryyang The time is 2013-12-04 22:52:01.336562598 +0800 HKT My favorite number is 6 Now you have 2.0000000000000004 problesms 3.141592653589793 55 55 yang gerry 10 7 7 10 0 0 0 false false false 1 2 3 true false no! 1 2 3 true false yes! bool(false) uint64(18446744073709551615) complex128((2+3i)) 3.14 你好 世界 世界 和平 Go rules? true 21 0.2 1.2676506002282295e+29 45 1024 leave out an infinite loop 1.4142135623730951 2i 9 20 27 >= 20 9 20 {1 2} {4 2} {1000000000 2} {1 2} &{1 2} {1 0} {0 0} &{0 0} &{11 9} as == [2 3 5 7 11 13] as[0] == 2 as[1] == 3 as[2] == 5 as[3] == 7 as[4] == 11 as[5] == 13 as[1:4] == [3 5 7] as[:3] == [2 3 5] as[4:] == [11 13] s1 len = 5 cap = 5 [0 0 0 0 0] s2 len = 0 cap = 5 [] s3 len = 2 cap = 5 [0 0] s4 len = 3 cap = 3 [0 0 0] [] 0 0 slice is nil 2**0 = 1 2**1 = 2 2**2 = 4 2**3 = 8 2**4 = 16 2**5 = 32 2**6 = 64 2**7 = 128 2**8 = 256 2**9 = 512 2**10 = 1024 1 2 4 8 16 32 64 128 256 512 1024 {40.68433 -74.39967} map[gerryyang:{100 200} wcdj:{-300 500}] map[math:{20 40} computer:{30 50}] The value: 20131129 The value: 20131130 The value: 20131130 Present? true The value: 0 The value: 0 Present? false 5 0 0 1 -2 3 -6 6 -12 10 -20 15 -30 21 -42 28 -56 36 -72 45 -90 1 2 3 5 8 13 21 34 55 89 OS X When's Saturday? In three days Good evening 5 f < 0 here 1.4142135623730951 &{15 20} 25 5 hello, writer at 2013-12-04 22:52:01.337206342 +0800 HKT, it didn't work */
有疑问加站长微信联系(非本文作者)