方法和接收者
-
方法定义
-
方法是一种作用于特定类型变量的函数,这种特定类型变量叫做接收者(Receiver),接收者的概念类似于其他语言中的this或者self
-
//方法的定义实例
//定义结构体
type Person struct{
name string
age int8
}
func NewPerson(name string, age int8)*Person{
return &Person{
name: name,
age:age,
}
}
//方法 Dream是为Person类型定义方法
func (p Person) Dream(){
fmt.Printf("%s\n", p.name)
}
func main() {
a := NewPerson("fdfv", int8(19))
(*a).Dream()
a.Dream()
}
-
接收者
//方法的定义实例 //定义结构体 type Person struct{ name string age int8 } func NewPerson(name string, age int8)*Person{ return &Person{ name: name, age:age, } } //方法 Dream是为Person类型定义方法 func (p Person) Dream(){ fmt.Printf("%s\n", p.name) } //接收者类型是指针 func (p *Person) SetAge(newAge int8){ p.age = newAge } //值接收者 修改值不会改变 func (p Person) SetAge1(newAge int8){ p.age = newAge } func main() { a := NewPerson("fdfv", int8(19)) (*a).Dream() a.Dream() fmt.Println(a.age) a.SetAge(int8(23)) fmt.Println(a.age) }
-
指针类型使用场合
-
需要修改接收者中的值
-
接收者是拷贝代价比较大的对象
-
保证一致性,如果有某个方法使用了指针接收者,那么其他方法也应该
-
结构体字段可见性和JSON序列化
如果一个go语言中定义的标识符是首字母大写的,那么就是对外可见的
包
-
一个文件夹下面只能有一个包,同样一个包的文件不能在多个文件夹下
-
包名可以不和文件夹的名字一样
-
匿名导包 import _"包的路径"
-
init() 函数没有参数和返回值,在包导入的时候自动执行,执行顺序:先全局声明->init()->main()
-
不允许导入包而不使用,不允许循环引用包
接口
-
定义:是一种类型,是一种抽象的类型
//接口 type dog struct { } func (d dog) say(){ fmt.Println("wangwang") } type cat struct { } func (c cat) say(){ fmt.Println("miaomiao") } //接口不管你是什么类型,它只管你要实现什么方法 //定义一个类型,一个抽象类型,只要实现了say()这个方法的类型都可以称为sayer类型 type sayer interface { say() } //不管传进来的什么类型,它只管你要实现什么方法 func do(arg sayer){ arg.say() } func main() { d := dog{} do(d) c := cat{} do(c) }
使用指针接收者实现接口:只有类型指针能够保存到接口变量中
同一类型可以实现多个接口,不同类型可以实现同一接口
空接口
//空接口
//接口中没有定义任何需要实现的方法时,该接口就是一个空接口
//任意类型都实现了空接口-->空接口变量可以储存任意值
type xxx interface {
}
//空接口的应用
//作为函数的参数
//可以作为map的value
func main() {
var x interface{}
x = "hello"
//fmt.Println(x)
x = 100
//fmt.Println(x)
ret, ok := x.(string)
if !ok{
fmt.Println("fss")
}else{
fmt.Println("fv", ret)
}
}
反射
定义
-
是指在程序运行期本身进行访问和修改的能力
-
reflect包
package main import ( "fmt" "reflect" ) func reflectType(x interface{}){ //不知道传来的变量是什么类型 //通过类型断言 //借助反射 obj := reflect.TypeOf(x) fmt.Println(obj, obj.Name(), obj.Kind()) fmt.Printf("%T\n", obj) } func main() { var a float32 = 1.234 reflectType(a) }
并发编程
并发与并行
-
goroutine->线程
func main() { //开启一个主goroutine去执行main函数 wg.Add(10000) for i := 0;i < 10000;i++{ go func(i int){ fmt.Println("hello", i) wg.Done() }(i) }//开启了一个goroutine去执行hello这个数 fmt.Println("hello main") //time.Sleep(time.Second) wg.Wait()//等待所有小弟执行完 }
-
GOMAXPROCS
通过runtime.GOMAXPORCS函数设置当前程序开发时占用的CPU逻辑核心数
-
go语言中操作系统线程和goroutine的关系
-
一个操作系统线程对应用户态多个goroutine
-
go程序可以同时使用多个操作系统线程
-
goroutine和OS线程时多对多的关系
-
-
channel 就是goroutine之间的连接,channel是可以让一个goroutine发送特定值到另一个goroutine的通信机制
-
channel是一种特殊的类型,像一个传送带或者队列,遵循先进先出的规则
-
通道有发送、接受、和关闭三种操作
func worker(id int,jobs <- chan int, results chan <- int){ for job := range jobs{ fmt.Printf("worker:%d start job:%d\n", id, job) results <- job*2 time.Sleep(time.Millisecond*500) fmt.Printf("worker:%d start job:%d\n", id, job) } } func main(){ //var ch1 chan int //需要初始化之后才能使用 //ch1 = make(chan int, 1) //ch1 <- 10 //x := <- ch1 //fmt.Println(x) //close(ch1) jobs := make(chan int, 100) results := make(chan int, 100) //开启三个goroutine for i := 0;i < 3;i++{ go worker(i, jobs, results) } //发送5个任务 for i := 0; i < 5; i++{ jobs <- i } close(jobs) for i := 0; i < 5; i++{ ret := <- results fmt.Println(ret) } }
-
-
select的使用
select { case <- ch1: ... case data := <- ch2: ... default: //默认操作 }
类似于switch语句,每个擦色会对应于一个通道的通信过程,使用select语句能提高代码可读性
并发同步和锁
/*互斥锁能够保证同一时间有且只有一个线程进入临界区,其他的线程则在等待锁;
当互斥锁释放后,等待的线程才能进入临界区
*/
var(
x int64
wg sync.WaitGroup
lock sync.Mutex
)
func add(){
for i := 0;i < 5000;i++{
lock.Lock()
x = x+1
lock.Unlock()
}
wg.Done()
}
func main(){
wg.Add(2)
go add()
go add()
wg.Wait()
fmt.Println(x)
}
读写锁分为两种:读锁和写锁
读锁:当一个线程获取读锁之后,其他的线程如果是获取读锁则继续获取,获取写锁则会等待
写锁:当一个线程获取写锁之后,其他的线程无论是获取读锁还是写锁都会等待
读写锁非常适合读多写少的场景
网络编程
互联网分层
-
应用层,传输层,网络层,数据链路层,物理层
TCP通信
-
TCP协议和TCP服务端
-
TCP服务端处理流程
-
监听端口
-
接受客户端请求建立链接
-
创建goroutine处理机制
-