语言个性
-
部署简略:
- 可间接编译成机器码执行
- 不依赖其余库
- 间接运行即可部署
- 动态类型语言:编译时即可查看出暗藏的问题
- 语言层面的并发:天生反对并发,充分利用多核
-
弱小的规范库:
- runtime 系统调度机制
- 高效的 GC 垃圾回收
- 丰盛的规范库
- 简略易学:25 个关键字,反对内嵌 C 语法,面向对象,跨平台
配置装置
Mac 下载地址:https://dl.google.com/go/go1….
装置门路:/usr/local/go
配置环境变量:
vi ~/.bash_profile
export GOPATH=$HOME/go
source ~/.bash_profile
常见问题
1.go.mod file not found in current directory or any parent directory
解决:go env -w GO111MODULE=auto
语法留神
- 表达式结尾不倡议加分号
-
导入多个包
import ( "fmt" "time" )
- 函数的花括号必须与函数名同行
vim hello.go
package main
import "fmt"
func main() {fmt.Println("Hello Go!")
}
编译并执行
go run hello.go
编译
go build hello.go
执行
./hello
变量 var
-
申明一个变量(默认值是 0)
var a int
-
申明一个变量,并初始化一个值
var b int = 100
-
初始化时省去类型,通过值主动匹配数据类型(不举荐)
var c = 100 var cc = "abcd" fmt.Printf("cc=%s,cc=%T",cc,cc)//cc=abcd,cc=string
-
省去 var 关键字,主动匹配(罕用)
e := 100 f := "abcd"
备注:办法 1.2.3 能够在函数体外,申明全局变量;4 只能在函数体内,申明局部变量
-
申明多行变量
var xx, yy int = 100, 200 var mm, nn = 100, "abc" var ( cc int = 100 dd bool = true ) fmt.Println("cc=",cc,"dd=",dd)
常量 const
常量是不容许批改的
const a int = 100
const (
BEIJING = 1
SHANGHAI = 2
)
iota:配合 const 应用,每行累加,第一行默认 0
const (
BEIJING = 10 * iota //0
SHANGHAI //10
SHENZHEN //20
)
const (
a, b = iota+1,iota+2//iota=0, a=1, b=2
c, d //iota=1, c=1, d=3
g, h = iota*2,iota*3//iota=3, g=6, h=9
)
函数
根本函数模式
func test(a string, b int) int {return 100}
多返回值
// 匿名
func test(a string, b int) (int, int) {return 666, 777}
// 无形参名 (初始化默认为 0)
func test(a string, b int) (r1 int, r2 int) {
r1 = 1000
r2 = 2000
return
}
import 与 init
hello.go
package main
import (
"GoStudy/lib1"
"GoStudy/lib2"
)
func main() {lib1.Lib1Test(); // 在内部调用的函数名首字母必须大写
lib2.Lib2Test();}
// 输入后果
//lib1.init()...
//lib2.init()...
//Lib1Test()...
//Lib2Test()...
lib1/lib1.go
package lib1
import "fmt"
func Lib1Test() {fmt.Println("Lib1Test()...")
}
func init() {fmt.Println("lib1.init()...")
}
lib2/lib2.go
package lib2
import "fmt"
func Lib2Test() {fmt.Println("Lib2Test()...")
}
func init() {fmt.Println("lib2.init()...")
}
留神:
-
导入匿名包(不执行包内的函数,但执行 init 办法)
import _ "GoStudy/lib2"
-
导入包别名
import l2 "GoStudy/lib2" func main() {l2.Lib2Test(); }
-
导入以后包中(可间接调用函数)
import . "GoStudy/lib2" func main() {Lib2Test(); }
指针 *
package main
import "fmt"
func changeValue(p *int) {*p = 10;}
func main() {
var a = 1
changeValue(&a)
//p = &a
//*p = 10
fmt.Println("a =",a) //a = 10
}
defer
函数完结前执行的机制(先入后出,在 return 办法后执行)
package main
import "fmt"
func func1() {fmt.Println("func1()...")
}
func func2() {fmt.Println("func2()...")
}
func func3() {fmt.Println("func3()...")
}
func returnAndDefer() int {defer func1()
defer func2()
defer func3()
return returnFunc()}
func returnFunc() int {fmt.Println("returnFunc()...")
return 0
}
func main() {returnAndDefer()
}
// 执行程序:returnFunc()...
func3()...
func2()...
func1()...
数组与动静数组
固定长度的数组
package main
import "fmt"
func test(arr []int) {arr[0] = 111
}
func main() {
// 固定长度的数组
var myArr []int
// 数组遍历
test(myArr)//myArr[0] 不变
for k, v := range myArr2 {fmt.Println("index=",k,"value=",v)
}
}
动静数组(切片 slice)
动静数组是援用传递,实际上传递的是数组的指针,指向同一块内存
不同长度的动静数组形参是一样的
package main
import "fmt"
func test(arr []int) {arr[0] = 111
}
func main() {
// 固定长度的数组
myArr := []int{1,2,3,4}
// 数组遍历
test(myArr)//myArr[0] 不变
for k, v := range myArr {fmt.Println("index=",k,"value=",v)
}
}
// 输入后果
index= 0 value= 111
index= 1 value= 2
index= 2 value= 3
index= 3 value= 4
注:_示意匿名变量
切片的申明形式
-
申明 slice1 是一个切片,并且初始化,默认值是 1,2,3,长度 len 是 3
slice1 := []int{1, 2, 3}
-
申明 slice2 是一个切片,然而并没有调配空间,须要 make 调配空间(初始化值是 0)
var slice2 = []int slice2 = make([]int, 3)
-
申明 slice3 是一个切片并通过 make 调配空间(初始化值是 0)
var slice3 []int = make([]int, 3)
-
申明 slice4 是一个切片并通过 make 调配空间(初始化值是 0),通过:= 推导出 slice4 是切片(罕用)
slice4 := make([]int, 3)
切片的追加
len:长度,示意左指针到右指针间的间隔
cap:容量,示意左指针到底层数组开端的间隔
切片的扩容机制:append 时,如果长度减少后超过容量,则将容量翻倍(5 -> 10 -> 20)
var numbers = make([]int, 3, 5)// 长度 3, 容量 5
fmt.Printf("len=%d,cap=%d,slice=%v",len(numbers),cap(numbers),numbers)
//len=3,cap=5,slice=[0 0 0]
向 numbers 追加一个元素 1
numbers = append(numbers, 1)
fmt.Printf("len=%d,cap=%d,slice=%v",len(numbers),cap(numbers),numbers)
//len=4,cap=5,slice=[0 0 0 1]
向 numbers 追加一个元素 2
numbers = append(numbers, 2)
fmt.Printf("len=%d,cap=%d,slice=%v",len(numbers),cap(numbers),numbers)
//len=5,cap=5,slice=[0 0 0 1 2]
向容量已满的 slice 追加元素
numbers = append(numbers, 3)
fmt.Printf("len=%d,cap=%d,slice=%v",len(numbers),cap(numbers),numbers)
//len=6,cap=10,slice=[0 0 0 1 2 3]
切片的截取
s := []int{1,2,3}
s1 := s[0:2]
s2 := make([]int, 3)
copy(s2, s)// 将 s 中的值,顺次 copy 到 s2
s1[0] = 100
fmt.Println(s)//[100 2 3]
fmt.Println(s1)//[100 2]
fmt.Println(s2)//[1 2 3]
map
申明形式
-
形式一:
- 申明 myMap1 是一种 map 类型,key 是 string,value 是 string
- 在应用 map 前,须要先用 make 给 map 调配数据空间
var myMap1 map[string]string myMap1 = make(map[string]string, 10) myMap1["a"] = "aaa" myMap1["b"] = "bbb"
-
形式二:
myMap2 := make(map[int]string) myMap2[0] = "a" myMap2[1] = "b" fmt.Println(myMap2) //map[0:a 1:b]
-
形式三
myMap3 := map[int]string { 0 : "a", 1 : "b", } fmt.Println(myMap3) //map[0:a 1:b]
应用形式
map 也是援用传递,做参数时传递的是指针地址
-
增加
myMap2 := make(map[int]string) myMap2[0] = "a" myMap2[1] = "b"
-
遍历
for k, v := range myMap2 {fmt.Printf("k=%d,v=%s\n",k,v) }
-
删除
delete(myMap2, 0)
-
批改
myMap2[0] = "c"
面向对象
构造体
-
定义
type Book struct { title string // 类的属性首字母大写示意私有,否则为公有 auth string }
-
应用
var book1 Book book1.title = "Golang" book1.auth = "Tom" fmt.Println(book1)//{Golang Tom} book2 := Book{title:"aaa",auth:"bbb"} fmt.Println(book2)//{aaa bbb} book3 := Book{"aaa","bbb"} fmt.Println(book3)//{aaa bbb}
-
传递(传递的是正本)
func changeBook(book Book) {book.title="XXX"} func main() { var book1 Book book1.title = "Golang" book1.auth = "Tom" changeBook(book1) fmt.Println(book1)//{Golang Tom} }
类
封装:类名,属性名,办法名首字母大写示意对外能够拜访
this 是调用该办法的对象的一个正本(拷贝)
func (this *Book) setName(title string) {this.title=title}
func (this Book) setAuth(auth string) {this.auth=auth}
func main() {book := Book{title:"aaa",auth:"bbb"}
book.setName("ccc")
book.setAuth("ddd")
fmt.Println(book)//{ccc bbb}
}
继承
package main
import "fmt"
type Human struct {
name string
sex string
}
type SuperMan struct {
Human
level int
}
func (this *Human) Eat() {fmt.Println("Human Eat...")
}
func (this *Human) Walk() {fmt.Println("Human Walk...")
}
func (this *SuperMan) Walk() {fmt.Println("SuperMan Walk...")
}
func (this *SuperMan) Fly() {fmt.Println("SuperMan Fly...")
}
func main() {tom := Human{"aaa","bbb"}
tom.Eat() //Human Eat...
tom.Walk()//Human Walk...
//s :=SuperMan{Human{"ccc","ddd"},100}
var s SuperMan
s.name = "Sss"
s.sex = "man"
s.level= 88
s.Walk()//SuperMan Walk...
s.Fly()//SuperMan Fly...}
多态
interface 实质是父类的一个指针
基本要素:
- 有一个父类(接口)
- 有子类实现了父类的全副接口办法
- 父类类型的变量(指针)指向(援用)子类的具体数据变量
package main
import "fmt"
type AnimalIF interface {Sleep()
GetColor() string}
type Cat struct {color string}
func (this *Cat) Sleep() {fmt.Println("Cat Sleep...")
}
func (this *Cat) GetColor() string {return this.color}
type Dog struct {color string}
func (this *Dog) Sleep() {fmt.Println("Dog Sleep...")
}
func (this *Dog) GetColor() string {return this.color}
func showAnimal(animal AnimalIF) {animal.Sleep()
fmt.Println("color=",animal.GetColor())
}
func main() {
var animal AnimalIF// 接口的数据类型:父类指针
animal = &Cat{"White"}
animal.Sleep()//Cat Sleep...
fmt.Println("color=",animal.GetColor())//color= White
dog := Dog{"Yellow"}
showAnimal(&dog)
//Dog Sleep...
//color= Yellow
}
万能数据类型 interface{}(空接口)
interface{} 类型断言机制:arg.(string)
package main
import "fmt"
type Book struct {tile string}
func test(arg interface{}){fmt.Println(arg)
// 断言
_, ok := arg.(string)
if !ok {fmt.Println("arg is not string")
}else{fmt.Println("arg is string")
}
}
func main() {book := Book{"Golang"}
test(book)//{Golang}
test(123)//123
test("hello")//hello
}
变量类型
-
变量 pair 对
-
type
- static type:int/string
- concrete type:interfece 所指的具体数据类型(零碎 runtime 看得见的类型)
- value
-
package main
import "fmt"
type Reader interface {ReadBook()
}
type Writer interface {WriteBook()
}
type Book struct {
}
func (this *Book) ReadBook() {fmt.Println("Read a book.")
}
func (this *Book) WriteBook() {fmt.Println("Write a book.")
}
func main() {b := &Book{}//b: pair<type:Book, value:Book{} 地址 >
var r Reader//r: pair<type: 空, value: 空 >
r = b //r: pair<type:Book, value:Book{} 地址 >
r.ReadBook()
var w Writer
w = r.(Writer)//w: pair<type:Book, value:Book{} 地址 >
// 断言有两步:失去动静类型 type,判断 type 是否实现了指标接口。// 这里断言胜利是因为 type 是 Book,而 Book 实现了 Writer 接口
w.WriteBook()}
反射 reflect
例 1:
package main
import (
"fmt"
"reflect"
)
func reflectNum(arg interface{}){fmt.Println("type:", reflect.TypeOf(arg))
fmt.Println("value:", reflect.ValueOf(arg))
}
func main() {
var num float64 = 1.34556
reflectNum(num)
//type: float64
//value: 1.34556
}
例 2:
package main
import (
"fmt"
"reflect"
)
type User struct {
Id int
Name string
Age int
}
func (this User) Call(){fmt.Printf("User: %v", this)
}
func DoFieldAndMethod(input interface{}){inputType := reflect.TypeOf(input)
inputValue := reflect.ValueOf(input)
// 遍历属性
for i := 0; i < inputType.NumField(); i++ {field := inputType.Field(i)
value := inputValue.Field(i).Interface()
fmt.Printf("%s:%v = %v\n",field.Name, field.Type, value)
}
//Id:int
//Name:string = Lilei
//Age:int = 18
// 遍历办法(留神指针类型的构造体办法无奈打印)for i := 0; i < inputType.NumMethod(); i++ {inputMethod := inputType.Method(i)
fmt.Printf("%s:%v\n",inputMethod.Name, inputMethod.Type)
}
//Call:func(main.User)
}
func main() {user := User{1, "Lilei", 18}
DoFieldAndMethod(user)
}
构造体标签 Tag
package main
import (
"fmt"
"reflect"
)
type User struct {
Name string `info:"name" doc:"姓名"`
Age int `info:"age" doc:"年龄"`
}
func findTag(input interface{}){inputType := reflect.TypeOf(input).Elem()
// 遍历属性
for i := 0; i < inputType.NumField(); i++ {taginfo := inputType.Field(i).Tag.Get("info")
tagdoc := inputType.Field(i).Tag.Get("doc")
fmt.Printf("info:%s doc:%s\n",taginfo, tagdoc)
}
}
func main() {
var u User
findTag(&u)
//info:name doc: 姓名
//info:age doc: 年龄
}
构造体标签在 json 中的利用
package main
import (
"fmt"
"encoding/json"
)
type User struct {
Name string `json:"name"`
Age int `json:"age"`
Hobby []string `json:"hobby"`}
func main() {user := User{"lilei", 18, []string{"dance","football"}}
//json 编码
jsonStr, err := json.Marshal(user)
if err != nil {fmt.Println("Json marshal error.")
return
}
fmt.Printf("json = %s",jsonStr)//json = {"name":"lilei","age":18,"hobby":["dance","football"]}
//json 解码
user1 := User{}
err = json.Unmarshal(jsonStr, &user1)
if err != nil {fmt.Println("Json unmarshal error.")
return
}
fmt.Println(user1)//{lilei 18 [dance football]}
}