一、一个简单的Go程序
下面这个程序是一个http请求,输出返回的body字段。panic会立即中断函数流程,执行延时调用。从下面这个程序可以看出通过go访问http非常简洁。
package main
import (
"net/http"
"io/ioutil"
"fmt"
)
func main() {
r, err := http.Get("http://httpbin.org/anything?hello=world")
if err != nil {
panic(err)
}
defer r.Body.Close()
body, err := ioutil.ReadAll(r.Body)
if err != nil {
panic(err)
}
fmt.Printf("body = %s\n", string(body))
}
二、Go语言数据类型
- uint 32位或64位
- uint8 无符号 8 位整型 (0 到 255)
- uint16 无符号 16 位整型 (0 到 65535)
- uint32 无符号 32 位整型 (0 到 4294967295)
- uint64 无符号 64 位整型 (0 到 18446744073709551615)
- int 32位或64位
- int8 有符号 8 位整型 (-128 到 127)
- int16 有符号 16 位整型 (-32768 到 32767)
- int32 有符号 32 位整型 (-2147483648 到 2147483647)
- int64 有符号 64 位整型 (-9223372036854775808 到 9223372036854775807)
- byte uint8的别名(type byte = uint8)
- rune int32的别名(type rune = int32),表示一个unicode码
- uintptr "无符号整型,用于存放一个指针是一种无符号的整数类型,没有指定具体的bit大小但是足以容纳指针。uintptr类型只有在底层编程是才需要,特别是Go语言和C语言函数库或操作系统接口相交互的地方。"
- float32 IEEE-754 32位浮点型数
- float64 IEEE-754 64位浮点型数
- complex64 32 位实数和虚数
- complex128 64 位实数和虚数
- string 字符串,默认值是空字符串,而非NULL
- array 数组
- struct 结构体,类似java里面的对象
- function 函数,默认值nil
- interface 接口,默认值nil
- map 字典,引用类型,默认值nil
- slice 切片,动态的数组,引用类型,默认值nil
- channel 通道,引用类型,默认值nil
三、 Go语言系统关键字
- break default func interface select
- case defer go map struct
- chan else goto package switch
- const fallthrough if range type
- continue for import return var
四、Go语言预定标识符
- append bool byte cap close complex
- complex64 complex128 uint16 copy FALSE float32
- float64 imag int int8 int16 uint32
- int32 int64 iota len make new
- nil panic uint64 print println real
- recover string TRUE uint uint8 uintprt
五、Go语言变量
package main
import "fmt"
func main() {
// 使用var定义变量,支持类型推断
var x int32
var s = "hello,world"
fmt.Println(x, s)
// 在函数内部,可以省略var关键字
y := 100
fmt.Println(y)
// 编译器将未使用的局部变量定义当作错误
//z := 200
}
六、Go语言--表达式
package main
import "fmt"
func main() {
x := 100
if x > 0 {
fmt.Println("x")
} else if x < 0 {
fmt.Println("-x")
} else {
fmt.Println("0")
}
switch {
case x > 0:
fmt.Println("x")
case x < 0:
fmt.Println("-x")
default:
fmt.Println("0")
}
for i:=0; i <5; i++ {
fmt.Println(i)
}
// 相当于while (x < 5) { ... }
for x < 5 {
fmt.Println(x)
x++
}
// 相当于while (true) { ... }
for {
fmt.Println(x)
x--
if x < 0 {
break
}
}
// 迭代遍历,除返回元素外,还返回索引
s := []int{100, 200, 300}
for i, n := range s {
fmt.Println(i, n)
}
}
七、Go语言--函数
package main
import (
"errors"
"fmt"
)
// 定义多个变量接受,多返回值
func div(a, b int) (int, error) {
if b == 0 {
return 0, errors.New("division by zero")
}
return a / b, nil
}
// 函数作为第一类型,可作为参数或返回值
func test(x int) func() {
// 匿名函数
return func() {
fmt.Println(x)
}
}
func main() {
a , b := 10, 2
c, err := div(a, b)
fmt.Println(c, err)
x := 100
f := test(x)
f()
}
八、Go语言--slice
切片是有三个字段的数据结构,指向底层数组的指针,切片访问元素的个数(长度),切片允许增长到的元素的个数(容量),这种数据结构便于使用和管理数据集。切片围绕动态数组的概念构建的,可以按需自动增长和缩小。切片是一个很小的对象,对底层数组进行了抽象,并提供相关的操作方法,切片的底层内存是在连续块中分配的。
package main
import "fmt"
func main() {
// 创建一个整型切片,其长度为3,容量为5
s := make([]int, 3, 5)
for i := 0; i < 3; i++ {
s[i] = i
}
// 创建一个整型切片,其长度和容量都是5
slice := []int{10, 20, 30, 40, 50}
// 创建一个新切片,其长度为2,容量为4
newslice := slice[1:3]
// 使用原有的容量来分配一个新元素
// 如果切片的底层数组没有足够的容量,append会创建一个新的底层数组,这个数组容量是原来的两倍
newslice = append(newslice, 60)
// 5 5
fmt.Println(cap(slice), len(slice))
// 4 3
fmt.Println(cap(newslice), len(newslice))
// 迭代切片,第一个值当前迭代索引位置,第二个该元素对应值的一份副本
for index, value := range newslice {
fmt.Printf("index:%d value:%d\n", index, value)
}
}
九、Go语言--map
map(映射)是一种数据结构,用于存储一系列无序的键值对。
package main
import "fmt"
func main() {
// 创建一个映射,键的类型是string,值的类型是int
dict := make(map[string]int)
// map[]
fmt.Println(dict)
// 创建一个映射,键和值的类型都是string,使用两个键值对初始化映射
colors := map[string]string{"red":"red","blue":"blue"}
// map[red:red blue:blue]
fmt.Println(colors)
// 从映射获取值并判断键是否存在
value, exits := colors["blue"]
if exits {
// blue
fmt.Println(value)
}
//删除键为blue的键值对
delete(colors, "blue")
// 使用range迭代映射
for key, value := range colors {
// key:red value:red
fmt.Printf("key:%s value:%s\n", key, value)
}
}
十、Go语言--结构体
结构类型可以用来描述一组数据值,这组值的本质既可以是原始的,也可以是非原始的。
package main
import "fmt"
// 结构体类型
type user struct {
name string
age byte
}
type manager struct {
// 匿名嵌入其他类型
user
title string
}
func main() {
var m manager
// 直接访问匿名字段成员
m.name = "james"
m.age = 34
m.title = "CTO"
fmt.Println(m)
}
十一、Go语言--指针
package main
// 内存地址是内存中每个字节单元的唯一编号
// 指针是一个实体,指针会分配内存空间,相当于一个专门用来保存地址的整型变量
func main() {
x := 10
// 获取地址保存到指针变量
var p *int = &x
// 用指针间接引用,并更新对象
*p +=10
// 0xc00002bf70 20
println(&x, x)
// 0xc00002bf70 20 0xc00002bf80
println(p, *p, &p)
}
十二、Go语言--方法
package main
import "fmt"
type student struct {
name string
age byte
}
// 方法能给用户定义的类型添加新的行为,方法实际上也是函数
// 只是在声明时,在func和方法名之间增加一个参数,成为recevier
func (s student) toString() string {
return fmt.Sprintf("%+v", s)
}
func main() {
s := student{"james", 34}
fmt.Println(s.toString())
}
十三、Go语言--接口
接口是用来定义行为的类型,这些被定义的行为不由接口直接实现,而是通过方法由用户定义的类型实现。
Go接口实现机制很简洁,只要目标类型方法包含接口声明的全部方法,就被视为实现了该接口,无需做显示声明。当然,目标类可以实现多个接口。
如果接口没有任何方法声明,那么就是一个空接口(interface{}),它的用途类似Object,可被赋值为任何类型的对象。
package main
import "fmt"
// 定义tester接口,定义两个方法
type tester interface {
test()
string() string
}
// 顶一个结构体data,实现接口tester
type data struct {}
func (d *data) test() {}
func (d data) string() string {
return "I Love China"
}
func main() {
var d data
// data没有实现tester,test()是指针接收者声明
var t tester = &d
t.test()
fmt.Println(t.string())
}
go多态的例子:
package main
import "fmt"
// notifer是一个定义了通知类行为的接口
type notifer interface {
notify()
}
// user定义了一个用户类型
type user struct {
name string
email string
}
// notify使用指针接收者实现了notifier的接口
func (u *user) notify() {
fmt.Printf("Sending user email to %s<%s>\n", u.name, u.email)
}
// admin定义了程序的管理员
type admin struct {
name string
email string
}
// notify使用指针接收者实现了notifier的接口
func (a *admin) notify() {
fmt.Printf("Sending user email to %s<%s>\n", a.name, a.email)
}
// sendNotification接受了一个实现notifer的值,并发送通知
func sendNotification(n notifer) {
n.notify()
}
func main() {
jack := user{"jack","jack@jd.com"}
// 创建一个user值并传给sendNotification
sendNotification(&jack)
rose := admin{"rose", "rose@jd.com"}
// 创建一个admin值并传给sendNotification
sendNotification(&rose)
}