环境配置
- GOROOT:SDK的安装路径
- PATH:添加$GOROOT/bin
- GOPATH:项目的目录(工作环境)
变量声明
// 先声明再赋值
var v1 int
v1 = 1
// 声明且赋值
var v2 = 2
// 声明且赋值2
v2_1 := 21
// 多变量赋值
var v3,v4,v5 = 3,"abc",5.0
// 多变量赋值2
v3_1,v4_1,v5_1 := 3,"abc",5.0
// 多变量声明
var v6,v7,v8 int
// 全局变量声明方式
var(
v9 = 100
v10 = "global"
v11 = 1.1
)
类型转换
var i int32 = 0
// int32 -> float
var fi float32 = float32(i)
// int32 -> int8
var i8 int8 = int8(i)
// int32 -> int64
var i64 int64 = int64(i)
// float -> string
var str string
str = fmt.Sprintf('%f',fi)
// 转字符串
strconv.Itoa(8)
// bool -> string
var b bool = true
str = fmt.Sprintf('%t',b)
// 另一种方式转成字符串
str = strconv.FormatInt(int64(i8), 10)
// 转数值
strconv.Atoi("8")
// string -> bool
// 转换失败会赋一个默认值
b, _ = strconv.ParseBool(str) // 这里忽略error
指针
- 基本数据类型,变量存的就是值
- 获取变量的地址用
&
- 指针类型,变量存的是一个地址,这个地址指向的空间才是实际值
- 获取指针类型所指向的值用
*
指针、slice切片、map、管道channel、interface等都是引用类型,调用方法时传递的是引用
// i的地址是 &i
var i int = 123
// 指针声明,将i的地址给p指针
// 注意:指针和实际类型必须一致
var p *int = &i
// 从指针获取i的值
var i2 int = *p
// str -> array
[]byte("hello world")
// array -> str
string([]byte("123"))
标识符命名
采用驼峰命名,如果首字母大写则其他的包也能访问,如果首字母大写则只能本包访问。
引入包和go path变量有关,引入时取包的绝对路径删除
$GOPATH/src/
前缀
进制
0
开头是8进制0x
开头是16进制- 正常是10进制
- 不支持写2进制
switch
var age int = 18
switch {
case age < 18:
fmt.Println("未成年")
fallthrough // 穿透到下一层
case age >= 18:
fmt.Println("成年人")
default:
fmt.Println("年龄不正常")
}
// type switch可以用来判断某个interface变量中实际指向的变量类型
var x interface{}
var y = 101
x = y
switch i := x.(type) {
case nil:
fmt.Printf("x的类型是%T",i)
case int:
fmt.Printf("x是int型")
case float64:
fmt.Printf("x是float64型")
case func(int) float64:
fmt.Printf("x是func(int)型")
case bool, string:
fmt.Printf("x是bool或string型")
default:
fmt.Printf("未知")
}
遍历
// 死循环
for {
}
// 布尔表达式循环
for true {
}
// 常规循环
for i := 0;i < 10; i++ {
}
// for range循环
for idx, val := range str{
}
在低版本的go sdk中如果str中有中文,使用range遍历没问题,使用传统遍历方式把str作为数组遍历可能会导致输出结果乱码,可以将string转换成rune在遍历:
[]rune(str)
函数
基本语法
func 函数名(形参列表)(返回值列表){
函数体
return 返回值
}
// 传递的是指针,*int是指针类型
func test(num *int) {
// 这里的 *num是num的实际值,是从num这个指针指向的地址取值
*num = *num + 10
}
func sum(a int,b int) int{
return a + b
}
// go语音的函数式
func useFunc(f func(int,int) int, a int, b int) int {
return f(a,b)
}
// 可以使用type简化func的写法(新版可能有问题)
type myFunc func(int,int) int
func useFunc(f myFunc, a int, b int) int {
return f(a,b)
}
// 调用可以这么玩
var mySum = sum
result := useFunc(sum,10, 20)
// 返回多个结果可以只要名称对应,return省略
func f(a int,b int)(sum int, sub int){
sum = a + b
sub = a - b
return
}
- init函数是特殊的函数,在运行时会最先被调用
- 匿名函数
sumResult := func (a int, b int) int { return a + b }(10,20) secondFunc := func (a int, b int) int { return a + b } secondSumResult := secondFunc(10,20)
- 闭包:一个使用外部变量的函数
// 返回一个n+a的函数,类似class // 注意:这个返回的函数如果多次使用,n会变 // 好处是n传入一次,就可以反复使用 func sum(n int) func(int) int { return func(a int) int { n += a return n } }
- defer:延迟执行某些操作,会将defer行的操作按照先后顺序压入栈中,等函数执行完毕后,会根据入栈的顺序先后执行,类似对整个函数加了一个final,defer操作行的变量会拷贝一份,函数中修改对defer不生效
包
- 引入写的是路径
- 使用写的是package
一般要求路径的最后一级与package名称一致
// 比如在abc/bcd/efg
package test
// ....代码省略
// 另一个包使用test的函数
package main
import (
// 引入刚刚的模块
"abc/bcd/efg"
)
// 使用
test.Xxx()
// 还可以使用别名的方式使用
package main
import (
t "abc/bcd/efg"
)
// 使用
t.Xxx()
内置函数
// new函数用来分配内存,主要分配值类型 ,返回的是一个指针
iptr := new(int)
// make函数用来分配内存,主要分配引用类型
make()
// 类型断言
var a interface{}
var b Cat = Cat{}
a = b
var c Cat
c = a.(Cat) // 此处为类型断言,如果类型一致则转换成功,如果类型不一致则抛出异常
c, ok = a.(Cat) // 此处为带检测类型断言,类型不一致也不会抛出异常
// 关闭函数,用来关闭管道
myChan := make(chan int, 10)
close(myChan)
异常处理
// defer + recover
// 这个代码放到函数中,会在函数运行结束之后运行
// 如果有异常会捕获到,并打印出来
defer func(){
err := recover()
if err != nil {
fmt.println(err)
}
}
// 自定义异常
myErr := errors.New("index out of array")
// panic函数如果参数为异常,则打印错误并终止程序
panic(myErr)
数组
// 声明数组
var arr1 [2]int
// 使用数组
arr1[0] := 1
arr1[1] := 1
// 数组的其他使用方式
var arr2 [2]int = [2]int {1, 2}
// 三个点表示填充后面的元素个数,可以省略
var arr3 = [...]int {1, 2}
// 使用对应下标初始化
var arr4 = [2]string{1:"张三", 0:"李四"}
// go中数组的引用传递
func test(arr *[3]int){
// 使用时加*取实际值
(*arr)[0] = 10
}
// 切片slice,使用数组初始化
// 将arr中1和2元素取出,生成切片
// arr[0:3] 等价于 arr[:3]
// arr[2:len(arr)] 等价于 arr[2:]
// arr[0:len(arr)] 等价于 arr[:]
slc := arr[1:3]
fmt.Println("切片中的元素个数:",len(slc))
fmt.Println("切片中的容量:",cap(slc))
// 有趣的是下面,这个是true,也就是说切片中存储的是数组中元素的地址
fmt.Println(&slc[0] == &arr[1])
// 切片的初始化方式,4是长度,10是容量(可选)
var s1 []int = make([]int,4,10)
var s2 []int = []int{1,2,3}
// 添加数据
s2 = append(s2,4,5,6)
// 三个点表示将slice打散传入
s2 = append(s2,s2...)
// 复制
copy(s2,s1)
// 二维数组
var aa1 [3][4]int = [3][4]int{{1,2,3,4},{},{}}
var aa2 = [3][4]int{{1,2,3,4},{},{}}
map
// map的key可以是bool,数字,string,指针,channel,接口,结构体,数组
// 注:slice、map和func不可以用
// key为int,值也为int
var m map[int]int
// key为int,值为(key为int和value为int)的map
var m map[int]map[int]int
// 使用前必须要先进行make分配空间,大小为选填
m = make(map[int]map[int]int, 16)
// 或者直接赋值,内部元素必须以逗号结尾
m1 := map[int]int{
1:1,
2:2,
}
// 删除某元素操作
delete(m1, 1)
// 查询操作,第一个返回值为该key的值,第二个元素为是否存在
val, ok := m1[2]
// 遍历
for k,v := range m1 {
}
面向对象
// 结构体是值类型,变量赋值给另一个变量会完全拷贝
type Cat struct{
Name string
Age int
Color string
}
// 结构体的使用
c := Cat{}
c := Cat{"name",1,"color"}
var c *Cat = new(Cat)
var c *Cat = &Cat{}
(*c).Name = "aaa"
// 赋值也可以使用下面的赋值
c.Name = ""
c.Age = 12
// 字段和类型完全相同的两个结构体可以互相转换,强转
// 结构体声明之后的内存分配基本是连续的
// 可以这样声明,相当于取了一个别名
type C Cat
// json转换时,因为作用域的原因,只能转换首字母大写的字段
// 解决方案:
type Person struct{
Name string `json:"name"`
Age int `json:"age"`
}
方法
方法只存在于结构体中,声明方式类似于函数,但是在go中函数和方法不是一个东西
type A struct{
Name string
}
// 这里是传值,会将调用该方法的复制一份传入该方法
// 参数可以使用args ...in传入不定长参数
func (a A) aTest(){
}
// 特殊的方法
// String() -> print会默认调用该方法
继承
使用匿名嵌套结构体表达继承
- 结构体可以使用匿名嵌套结构体的所有字段和方法,不论是首字母大写还是小写
- 如果嵌套的多个结构体(多重继承)有相同的方法和字段,使用时需要指定到底要用谁的方法和字段,否则编译器会报错
type Goods struct{
Name string
Price float64
}
type Book struct {
Goods // 嵌套匿名结构体
Writer string
}
// 使用
book := &Book{}
book.Writer = "张三"
book.Goods.Name = "书"
book.Goods.Price = 128.0
// 也可以这样用,取值优先级是 本结构体 > 嵌套结构体
book.Name = "go语音从入门到放弃"
book.Price = 100000000000.00
接口
接口实现不需要显示指定,只有实现了接口所有方法,才会被认为是实现了该接口
基本语法
type 接口名 interface {
方法1(参数列表) 返回值
方法2(参数列表) 返回值
}
type Usb interface {
Start()
Stop()
}
type Phone struct {
}
func (this Phone) Start(){
fmt.Println("手机开始工作")
}
func (this Phone) Stop(){
fmt.Println("手机停止工作")
}
type Camera struct{
}
func (this Camera) Start(){
fmt.Println("相机开始工作")
}
func (this Camera) Stop(){
fmt.Println("相机停止工作")
}
type Computer struct {
}
func (this Computer) Work(usb Usb){
usb.Start()
usb.Stop()
}
func main(){
// 使用方式如下
p := Phone{}
computer := Computer{}
computer.Work(p)
}
多态
go语言使用接口实现