基础知识
- 运行:go run
- 编译:go build
- 声明变量 var a="xxx", var b int =1,声明后却没有给出对应的初始值时,变量将会初始化为 零值 。 例如,int 的零值是0。:=是简写
- import ("fmt" "math")导入包
- const 用于声明一个常量,常数表达式可以执行任意精度的运算,数值型常量没有确定的类型,直到被给定某个类型,可以根据上下文
- for 是 go 唯一的循环结构
当 while 来用:for i<=3 普通初始/条件/控制: for n:=0; i<=5; i++ 也可以不带条件用 return,break,continue 后面跟{ }
- 在条件语句之前可以有个声明语句,if num:=9; num<0{ }else if{ }else{ }, 条件可以加圆括号, 但不能没有花括号!
- go 没有三目运算符
- case 里没有 break (隐式存在,如果要继续执行下一条 case 中内容使用 fallthrough 关键字。
- case 后可以不使用常量
- 定义数组:1、var a [5]int, 2、b:=[5]{1,2,3,4,5}, 3、c:=make ([]string, 3),4、var numbers = [5]int{1, 2, 3, 4, 5}
- 创建 map 需要内建函数 make: make(map[key-type]val-type), 使用 name[key]=val 设置,删除 delete (name, key), 还可以选择是否接收第二个返回值,表明是否存在这个键。“_”(空白标识符 blank identifier)忽略一些值
- range 在字符串中迭代 unicode 码点,第一个返回值是字符的起始字节,第二个是字符本身
- 可变参数函数:func (slice…)
- %v 自动类型识别
- go 语言中的字符串是一个只读的 byte 类型,所以用字符串函数需要重新赋值回去
- go 字符串是 UTF-8 编码文本,等价于 []byte,可以使用 utf8. RuneCountInString 计算 rune 个数,range 循环处理字符串每个 rune 以及在字符串中的偏移量
- fmt.Println(&person{name: "Ann", age: 40})输出 &{Ann 40}
- defer,为了在函数执行完毕后,及时的释放资源 当 go 执行到一个 defer 时,不会立即执行 defer 后的语句,而是将 defer 后的语句压入到一个栈中[暂时称该栈为 defer 栈], 然后继续执行函数下一个语句。 当函数执行完毕后,在从 defer 栈中,依次从栈顶取出语句执行 (注: 遵守栈先入后出的机制) 在 defer 将语句放入到栈时, 也会将相关的值拷贝同时入栈。
- 将 []byte 类型的 v 转化为 string, json. Marshal 就不会对内容进行 base 64 编码了。
- 完整的 slice[start, end, max_cap]//go 没有步长的概念
- bin 项目编译的二进制文件,pkg 项目编译的中间产物,加速编译,src 项目源码
- 批量声明格式:var (a int \n b string)
- golang 中函数局部变量,不管是是不是动态 new 出来的,分配在堆还是栈是由编译器做逃逸分析之后做出的决定
- .1 当发现变量的作用域没有跑出函数范围,就可以在栈上,反之则必须分配在堆,与变量是 var、new 或者 make 没有任何关系。
- .2 如果变量太大,即使没有跑出函数范围,也会在堆上,同样,与变量是 var、new 或者 make 没有任何关系。
- .3 如果栈空间不足,也会在堆空间申请内存
- errors.New 使用给定的错误信息构造一个基本的 error 值,返回值 nil 代表没有错误。
- 如果一个数是 byte 类型,需要传入参数为[]byte, 可以写作[]byte{byte}
- io. ReadFull (*reader,[]byte)可以读取第二个参数大小的元素
- 避免闭包内部引用外部变量,尽量使用局部变量,防止多个闭包共享一个外部变量(可以作为参数)
rune: int 32 别名,表示一个 unicode 码
byte: uint 8 别名
字符串 传统字符串由字符组成,go 字符串由字节 byte 组成 UTF-8 编码,英文占一个字符,汉字占三个字符
占位符: %q 表示 单引号围绕的字符字面值,由 Go 语法安全地转义 %s 表示 字符串 %v 表示 默认格式 eg. 字节切片类型[]bytes %s 打印字符 %v 打印切片
[]byte 和 string 的关系
string是一种结构,底层是byte。因为string的指针指向的内容是不可以更改的,所以每更改一次字符串,就得重新分配一次内存,之前分配空间的还得由gc回收,这是导致string操作低效的根本原因。
- string 可以直接比较,而[]byte 不可以,所以[]byte 不可以当 map 的 key 值。
- 因为无法修改 string 中的某个字符,需要粒度小到操作一个字符时,用[]byte。
- string 值不可为 nil,所以如果你想要通过返回 nil 表达额外的含义,就用[]byte。
- []byte 切片这么灵活,想要用切片的特性就用[]byte。
- 需要大量字符串处理的时候用[]byte,性能好很多。
字符串操作
strconv hello strings. Contains () 包含 strings. Count ()个数 strings. HasPrefix ()前缀 strings. HasSuffix ()后缀 strings. Join ([]string{"he","llo"},"-") strings. Index ()索引 strings. Repeat ()重复 strings. Replace (a,"e","E",-1) strings. Split ("a-b-c","-") [a b c]
时间处理
格式化时间 Format ("2006-01-02 15:04:05")
进程信息
接口
方法签名的集合叫做:接口 (Interfaces)。 要在 Go 中实现一个接口,我们只需要实现接口中的所有方法。 type geometry interface { method1 (参数列表) 返回值列表 method2 (参数列表) 返回值列表 } } func (t 自定义类型) method1 (参数列表)返回值列表{ //方法实现 }
作用
- 作为方法的收束器,进行面向对象设计
- 作为各种数据的承载着,可以用来接受函数参数等
- 空接口实现接收任意类型的函数类型
- 空接口作为 map 的值
注意事项
(1)接口本身不能创建实例,但是可以指向一个实现了该接口的自定义类型的变量 (2)接口中所有的方法都没有方法体,即都是没有实现的方法。 (3)在 Go 中,一个自定义类型需要将某个接口的所有方法都实现,我们说这个自定义类型实现了该接口。 (4)一个自定义类型只有实现了某个接口,才能将该自定义类型的实例(变量)赋给接口类型。 (5)只要是自定义数据类型就可以实现接口,不仅仅是结构体类型。 (6)一个自定义类型可以实现多个接口。 (7)Go 接口不能有任何变量。 (8)一个接口可以继承多个别的接口,这时如果要实现这个接口必须实现它继承的所有接口的方法。在低版本的 Go 编辑器中,一个接口继承其他多个接口时,不允许继承的接口有相同的方法名。比如 A 接口继承 B、C 接口,B、C 接口的方法名不能一样。高版本的 Go 编辑器没有相关问题。 (9)interface 类型默认是一个指针(引用类型),如果没有对 interface 初始化就使用,那么会输出 nil。 (10)空接口 interface{}没有任何方法,所以所有类型都实现了空接口,即我们可以把任何一个变量赋给空接口类型。
底层实现
Go 的 interface 是由两种类型来实现的:iface 和 eface。 eface是不包含方法的interface,即空interface
iface 源代码
type iface struct {
tab *itab
data unsafe. Pointer
}
itab一部分是唯一确定包含该interface的具体结构类型,一部分是指向具体方法集的指针。
itab的源代码
type itab struct {
inter *interfacetype //此属性用于定位到具体interface
_type *_type //此属性用于定位到具体interface
hash uint32 // copy of _type.hash. Used for type switches.
_ [4]byte
fun [1]uintptr // variable sized. fun[0]==0 means _type does not implement inter.
}
interfacetype源码
type interfacetype struct {
typ _type
pkgpath name
mhdr []imethod
}
type imethod struct {
name nameOff
ityp typeOff
}
侵入式与非侵入式
侵入式
public interface IPersonService {
String getName();
Integer getAge();
}接口
public class PersonService implements IPersonService{
@Override
public String getName() {
return "小明";
}
@Override
public Integer getAge() {
return 12;
}
}
实现接口的类
非侵入式
package main
import "fmt"
// Person 定义接口
type Person interface {
GetName() string
GetAge() uint32
}
// Student 定义类型
type Student struct {
Name string
Age uint32
}
func (s Student) GetName() string{
return s.Name
}
func (s Student) GetAge() uint32{
return s.Age
}
func main() {
var student Student
student.Age = 12
student.Name = "小明"
var person Person
person = student
fmt.Printf("name:%s,age: %d\n", person.GetName(), person.GetAge())
}