Go编程基础-学习2

1350368559 · · 750 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

46.结构struct

Go 中的struct与C中的struct非常相似,并且Go没有class
使用 type <Name> struct{} 定义结构,名称遵循可见性规则

package main
import "fmt"
type persion struct {
    Name string
    Age int
}
func main() {
    a := persion{}
    a.Name="david"
    a.Age=13
    fmt.Println(a)
}
{david 13}

package main
import "fmt"
type persion struct {
    Name string
    Age int
}
func main() {
    a := persion{Name:"david"}
    fmt.Println(a)
}
{david 0} //0是int的初始值

package main
import "fmt"
type persion struct {
    Name string
    Age int
}
func main() {
    a := persion{Name:"david",Age:13}
    fmt.Println(a)
}
{david 13}

package main
import "fmt"
type persion struct {
    Name string
    Age int
}
func main() {
    a := persion{"david",28}
    fmt.Println(a)
}
{david 28}

struct也是一个值类型,传递的时候也是值拷贝

package main
import "fmt"
type persion struct {
    Name string
    Age int
}
func main() {
    a := persion{
        Name:"david",
        Age:28,
        }
    fmt.Println(a)
    A(a)
    fmt.Println(a)
}
func A(per persion){
    per.Age = 13
    fmt.Println("A",per)
}
{david 28}
A {david 13}
{david 28}

支持指向自身的指针类型成员

如何真正修改Age为13呢?答案是采用指针方式修改内存地址中的值,指针值传递
package main
import "fmt"
type persion struct {
    Name string
    Age int
}
func main() {
    a := persion{
        Name:"david",
        Age:28,
        }
    fmt.Println(a)
    A(&a)
    fmt.Println(a)
}
func A(per *persion){
    per.Age = 13
    fmt.Println("A",per)
}
{david 28}
A &{david 13}
{david 13}//这里修改了内存中的age为13

package main
import "fmt"
type persion struct {
    Name string
    Age int
}
func main() {
    a := persion{
        Name:"david",
        Age:28,
        }
    fmt.Println(a)
    A(&a)
    B(&a)
    fmt.Println(a)
}
func A(per *persion){
    per.Age = 13
    fmt.Println("A",per)
}
func B(per *persion){
    per.Age = 15
    fmt.Println("B",per)
}
{david 28}
A &{david 13}
B &{david 15}
{david 15}//如果有一个B函数,修改age为15,最终age等于15

如果有(100个)多个函数需要调用?每次都需要取地址符号,很麻烦,怎么办? 用指针保存,把a变为一个指向结构的指针呢?初始化的时候就把地址取出来
package main
import "fmt"
type persion struct {
    Name string
    Age int
}
func main() {
    a := &persion{    //定义a是一个指针
        Name:"david",
        Age:28,
        }
    fmt.Println(a)
    A(a) //这里直接调用即可,不用取地址
    B(a) //这里直接调用即可,不用取地址
    fmt.Println(a)
}
func A(per *persion){
    per.Age = 23
    fmt.Println("A",per)
}
func B(per *persion){
    per.Age = 25
    fmt.Println("B",per)
}
&{david 28}//这里可以看到a是一个指向struct的指针
A &{david 23}
B &{david 25}
&{david 25}

如果此时我需要要像class一样对a的属性性操作,怎么做?a.Name = "ok"
package main
import "fmt"
type persion struct {
    Name string
    Age int
}
func main() {
    a := &persion{"david", 28,}
    a.Name="ok" //这里直接修改属性的值
    fmt.Println(a)
    A(a)
    fmt.Println(a)
}
func A(per *persion) {
    per.Age = 23
    fmt.Println("A", per)
}
&{ok 28}
A &{ok 23}
&{ok 23}

支持匿名结构,可用作成员或定义成员变量

package main
import "fmt"
func main() {
    a := struct{
        Name string
        Age int
        }{
            Name:"david",
            Age:19,
            }
    fmt.Println(a)
}
{david 19}
 也可以定义指针类型的匿名结构
package main
import "fmt"
func main() {
    a := &struct{ //a是没有名称的匿名结构,定义指针类型结构
        Name string
        Age int
        }{  //需要对结构属性(字面值)赋值
            Name:"david",
            Age:19,
            }
    fmt.Println(a)
}
&{david 19}

匿名结构是否可以嵌套其他结构中呢?可以
package main
import "fmt"
type person struct {
    Name string
    Age int
    Contact struct {
        Phone,City string
    }
}
func main() {
    a := person{}
    fmt.Println(a)
}
{ 0 { }} //0是int型的Age初始值,{ }是Contact的结构

package main
import "fmt"
type person struct {
    Name string
    Age int
    Contact struct {
        Phone,City string
    }
}
func main() {
    a := person{Name:"david",Age:13}
    a.Contact.City="sahgnhai"//匿名结构赋值的方法
    a.Contact.Phone="111111111"
    fmt.Println(a)
}
{david 13 {111111111 sahgnhai}}

什么是匿名字段?
package main
import "fmt"
type person struct {
    string //这就是匿名字段,没有定义属性的名字,只是定义了类型
    int
}
func main() {
    a := person{"david",19}//注意,赋值顺序是string、int,不能对调,否则报错
    fmt.Println(a)
}
{david 19}

匿名结构也可以用于map的值
可以使用字面值对结构进行初始化
允许直接通过指针来读写结构成员
相同类型的成员可进行直接拷贝赋值
支持 == 与 !=比较运算符,但不支持 > 或 <
支持匿名字段,本质上是定义了以某个类型名为名称的字段

结构也是一种类型,相同的类型之间,变量可以进行赋值
package main
import "fmt"
type person struct {
    Name string
    Age int
}
func main() {
    a := person{"david",19}
    var b person
    b=a //把a赋值给b,打印出来b和a是一样的
    fmt.Println(b)
}
{david 19}

struce是一种类型,所以可以比较?
a和b虽然内容包含相同,但是名称不同,就是不同类型,没有可比性,无法比较,所以报错,只有用相同的struct person才可以比较。
package main
import "fmt"
type person1 struct {
    Name string
    Age int
}
type person2 struct {
    Name string
    Age int
}
func main() {
    a := person1{"david",19}
    b := person2{"david",19}
    fmt.Println(a == b )
}
invalid operation: a == b (mismatched types person1 and person2)

package main
import "fmt"
type person struct {
    Name string
    Age int
}
func main() {
    a := person{"david",19}
    b := person{"david",19}
    fmt.Println(a == b )
}
true

package main
import "fmt"
type person struct {
    Name string
    Age int
}
func main() {
    a := person{"david",19}
    b := person{"david",20}
    fmt.Println(a == b )
}
false

嵌入结构作为匿名字段看起来像继承,但不是继承
可以使用匿名字段指针

package main
import (
    "fmt"
)
type human struct {
    Sex int
}
type teacher struct {
    human
    Name string
    Age int
}
type student struct {
    human
    Name string
    Age int
}
func main() {
    a := teacher{Name:"joe",Age:19}
    b := student{Name:"joe",Age:20}
    fmt.Println(a,b )
}
{{0} joe 19} {{0} joe 20} //human的int默认值0已经嵌套进去了

package main
import (
    "fmt"
)
type human struct {
    Sex int
}
type teacher struct {
    human
    Name string
    Age int
}
type student struct {
    human
    Name string
    Age int
}
func main() {
    a := teacher{Name:"joe",Age:19,Sex:0}
    b := student{Name:"joe",Age:20,Sex:1}
    fmt.Println(a,b )
}
hello.go:19:36: unknown field 'Sex' in struct literal of type teacher
hello.go:20:36: unknown field 'Sex' in struct literal of type student
//这里报错了,因为初始化方法错误,应该怎么定义呢?

方法1:human在teacher中被当做匿名字段,所以定义human:{Sex:0}
package main
import (
    "fmt"
)
type human struct {
    Sex int
}
type teacher struct {
    human
    Name string
    Age int
}
type student struct {
    human
    Name string
    Age int
}
func main() {
    a := teacher{Name:"joe",Age:19,human:human{Sex:0}}//human在teacher中被当做匿名字段变量,给变量赋值
    b := student{Name:"joe",Age:20,human:human{Sex:1}}
    fmt.Println(a,b )
}
{{0} joe 19} {{1} joe 20}

package main
import (
    "fmt"
)
type human struct {
    Sex int
}
type teacher struct {
    human
    Name string
    Age int
}
type student struct {
    human
    Name string
    Age int
}
func main() {
    a := teacher{Name:"joe",Age:19,human:human{Sex:0}}
    b := student{Name:"joe",Age:20,human:human{Sex:1}}
    a.Name="joe2"
    a.Age=13
    a.human.Sex=100 //标准方法,防止有多个导入字段重复报错
    a.Sex=100 //sex已经被当做teacher的一个属性嵌入,human结构嵌入,把嵌入结构的字段sex都给了外层结构teacher
    fmt.Println(a,b )
}
{{100} joe2 13} {{1} joe 20}

如果匿名字段和外层结构有同名字段,应该如何进行操作?

package main
import (
    "fmt"
)
type A struct {
    B
    Name string
}
type B struct {
    Name string
}

func main() {
    a := A{Name: "A", B: B{Name: "B"}}
    fmt.Println(a.Name,a.B.Name) //分别输出a和b的name值A和B
}
A B

如果A中不存在Name字段,那么打印a.Name是什么呢?答案是B
package main
import (
    "fmt"
)
type A struct {
    B
}
type B struct {
    Name string
}

func main() {
    a := A{B: B{Name: "B"}}
    fmt.Println(a.Name,a.B.Name)//此时的a.Name=B,此时a.Name,a.B.Name写法等价
}
B B

package main
import (
    "fmt"
)
type A struct {
    B
    C
}
type B struct {
    Name string
}

type C struct {
    Name string
}
func main() {
    a := A{B: B{Name: "B"},C: C{Name: "C"}}
    fmt.Println(a.Name,a.B.Name,a.C.Name)
}
ambiguous selector a.Name//报错提示有重名的字段,因为a.Name此时到底等于a.B.Name还是等于a.C.Name呢?完全不清楚

47.方法method

Go 中虽没有class,但依旧有method

只能为同一个包中的类型结构定义方法method呢?通过显示说明receiver来实现与某个类型的组合,编译器根据接受者的类型来判断是哪一个类型的方法

package main
import (
    "fmt"
)
type A struct {
    Name string
}
type B struct {
    Name string
}
//定义一个链接到struct A的方法print
func(a A)Print(){ //局部变量a的接受者类型是struct:A,所以定义的方法print是struct A的类型方法
    fmt.Println("A")
}
func main(){
    a :=A{} //声明一个结构A
    a.Print()//然后a调用Print方法,打印结果A
}
A

package main
import (
    "fmt"
)
type A struct {
    Name string
}
type B struct {
    Name string
}
//定义一个链接到struct A的方法print
func(a A)Print(){ //局部变量a的接受者类型是struct:A,所以定义的方法print是struct A的类型方法
    a.Name = "A"
    fmt.Println("A")
}
func(b B)Print(){ //定义一个连接到B结构的方法Print
    b.Name="B"
    fmt.Println("B")
}
func main(){
    c :=A{} //声明一个结构A
    c.Print()//然后a调用Print方法,打印结果A
    d :=B{}
    d.Print()//注意这里调用方法使用c.Print()和d.Print(),不能使用Print(),否则编译器不清楚是c还是d的Print()方法
}
A
B

Receiver 可以是类型的值或者指针

package main
import (
    "fmt"
)
type A struct {
    Name string
}
type B struct {
    Name string
}
//定义一个链接到struct A的指针类型的方法Print
func(a *A)Print(){ //局部变量a的接受者类型是指针类型struct:A,所以定义的方法print是指针类型struct A
    a.Name = "AAA" //引用类型是指针类型拷贝,操作了内存中对象,所以a.Name = "AAA"保存到内存中
    fmt.Println("A")
}
func(b B)Print(){
    b.Name="BB" //值类型以值传递,只是得到一个拷贝副本,结束方法之后失效,打印空
    fmt.Println("B")
}
func main(){
    a :=A{} //声明一个结构A
    a.Print()//然后a调用Print方法,打印结果A
    fmt.Println(a.Name)
    b :=B{}
    b.Print()
    fmt.Println(b.Name)
}
A
AAA
B

不存在方法重载
可以使用值或指针来调用方法,编译器会自动完成转换

package main
import (
    "fmt"
)
type TZ int //可以为任何类型绑定方法Print(),非常灵活,可以对int类型做高级的绑定定义等
func (a *TZ)Print(){
    fmt.Println("TZ")
}
func main(){
    var a TZ
    a.Print()
}
TZ //这里打印TZ

从某种意义上来说,方法是函数的语法,因为receiver其实就是
方法所接收的第1个参数(Method Value vs. Method Expression)

package main
import (
    "fmt"
)
type TZ int

func (a *TZ)Print(){
    fmt.Println("TZ")
}
func main(){
    var a TZ
    a.Print()//Method Value,已经声明了receiver a,通过类似类的方法调用的形式
    (*TZ).Print(&a)//Method Expression,通过类型(*TZ),把变量&a作为receiver(第一个参数)传给对应的Print方法,而不是类型变量调用方法
}
TZ
TZ

如果外部结构和嵌入结构存在同名方法,则优先调用外部结构的方法
类型别名不会拥有底层类型所附带的方法

方法访问权限的问题:
方法可以调用结构中的非公开字段,同一包package中方法访问权限认为公开的,不是私有的,相对其他包package才认为是私有字段:

package main
import (
    "fmt"
)
type A struct {
    name string
}

func (a *A)Print(){
    a.name = "123"
    fmt.Println(a.name)
}
func main() {
    a:=A{}
    a.Print()
    fmt.Println(a.name)
    }
    输出:
    123
    123

根据为结构增加方法的知识,尝试声明一个底层类型为int的类型,
并实现调用某个方法就递增100。0+100=100
如:a:=0,调用a.Increase()之后,a从0变成100。

package main
import (
    "fmt"
)
type  TZ int

func (tz *TZ)Increase(num int){
    *tz += TZ(num)//这里需要经num强制类型转换为TZ型,否则报错,因为TZ和int是不同的类型
}
func main() {
    var a TZ //声明a是TZ类型,a的初始值是0
    a.Increase(100)
    fmt.Println(a)
    }
    100

48.接口interface

接口是一个或多个方法签名的集合
只要某个类型拥有该接口的所有方法签名,即算实现该接口,无需显示声明实现了哪个接口,这称为 Structural Typing

package main
import (
    "fmt"
)
type  USB interface{ //定义一个USB接口
    Name() string //返回USB名称
    Connect()     //连接的方法
}

type PhoneConnecter struct{ //定义手机连接器结构,有一个name变量
    name string
}
//怎么样用结构让USB实现呢?实现就是为结构添加方法,对应USB中的Name()
func (pc PhoneConnecter)Name() string  { //定义一个receiver是PhoneConnecter结构的Name()方法,返回一个string类型的pc.name
    return pc.name
}
//怎么样用结构让USB实现呢?实现就是为结构添加方法,对应USB中的Connect()
func (pc PhoneConnecter)Connect(){ //定义一个receiver是PhoneConnecter结构的Connect()方法,打印pc.name
    fmt.Println("Connect",pc.name)
}

func main(){
    var a USB //定义一个USB接口
    a = PhoneConnecter{"PhoneConnecter"}//初始化一个name=PhoneConnecter的手机连接器(具有接口USB属性)
    a.Connect()
}
Connect PhoneConnecter

package main
import (
    "fmt"
)
type  USB interface{ //定义一个USB接口
    Name() string //返回USB名称
    Connect()     //连接的方法
}

type PhoneConnecter struct{ //定义手机连接器结构,有一个name变量
    name string
}
//怎么样用结构让USB实现呢?实现就是为结构添加方法,对应USB中的Name()
func (pc PhoneConnecter)Name() string  { //定义一个receiver是PhoneConnecter结构的Name()方法,返回一个string类型的pc.name
    return pc.name
}
//怎么样用结构让USB实现呢?实现就是为结构添加方法,对应USB中的Connect()
func (pc PhoneConnecter)Connect(){ //定义一个receiver是PhoneConnecter结构的Connect()方法,打印pc.name
    fmt.Println("Connect",pc.name)
}
func Disconnect(usb USB){
    fmt.Println("Disconnected")
}

func main(){
    //var a USB 这里省略定义一个USB接口,因为PhoneConnecter已经具备了USB的Name属性和Connect方法,就已经实现了USB接口,可以直接调用,也可以Disconnect
    a := PhoneConnecter{"PhoneConnecter"}//初始化一个name=PhoneConnecter的手机连接器(具有接口USB属性)
    a.Connect()
    Disconnect(a)
}
Connect PhoneConnecter
Disconnected

接口只有方法声明,没有实现,没有数据字段
接口可以匿名嵌入其它接口,或嵌入到结构中

package main
import (
    "fmt"
)
type  USB interface{ //定义一个USB接口
    Name() string //返回USB名称
    Connecter     //连接的方法
}
type Connecter interface{ //这里的Connecter具备Connect()方法,所以USB中直接嵌入Connecter
    Connect()
}
type PhoneConnecter struct{ //定义手机连接器结构,有一个name变量
    name string
}
//怎么样用结构让USB实现呢?实现就是为结构添加方法,对应USB中的Name()
func (pc PhoneConnecter)Name() string  { //定义一个receiver是PhoneConnecter结构的Name()方法,返回一个string类型的pc.name
    return pc.name
}
//怎么样用结构让USB实现呢?实现就是为结构添加方法,对应USB中的Connect()
func (pc PhoneConnecter)Connect(){ //定义一个receiver是PhoneConnecter结构的Connect()方法,打印pc.name
    fmt.Println("Connect",pc.name)
}
func Disconnect(usb USB){
    fmt.Println("Disconnected")
}

func main(){
    //var a USB //定义一个USB接口
    a := PhoneConnecter{"PhoneConnecter"}//初始化一个name=PhoneConnecter的手机连接器(具有接口USB属性)
    a.Connect()
    Disconnect(a)
}
Connect PhoneConnecter
Disconnected

package main
import (
    "fmt"
)
type  USB interface{ //定义一个USB接口
    Name() string //返回USB名称
    Connecter     //连接的方法
}
type Connecter interface{ //这里的Connecter具备Connect()方法,所以USB中直接嵌入Connecter
    Connect()
}
type PhoneConnecter struct{ //定义手机连接器结构,有一个name变量
    name string
}
func (pc PhoneConnecter)Name() string  { //定义一个receiver是PhoneConnecter结构的Name()方法,返回一个string类型的pc.name
    return pc.name
}
func (pc PhoneConnecter)Connect(){ //定义一个receiver是PhoneConnecter结构的Connect()方法,打印pc.name
    fmt.Println("Connect",pc.name)
}
//这里只是单纯的disconnected,但是不知道谁断开了连接,不知道断开的是不是一个PhoneConnecter,怎么办呢?
func Disconnect(usb USB){
    if pc,ok :=usb.(PhoneConnecter);ok { //ok,pattern模式,类型判断USB是否是PhoneConnecter结构?如果成立ok=true,打印pc.name
        fmt.Println("Disconnected",pc.name)
        return
    }
    fmt.Println("Unknow device")
}
func main(){
    //var a USB //定义一个USB接口
    a := PhoneConnecter{"PhoneConnecter"}//初始化一个name=PhoneConnecter的手机连接器(具有接口USB属性)
    a.Connect()
    Disconnect(a)
}
Connect PhoneConnecter
Disconnected PhoneConnecter

49.类型断言

通过类型断言的ok pattern可以判断接口中的数据类型
使用type switch则可针对空接口进行比较全面的类型判断

package main
import (
    "fmt"
)
type empty interface{

}
type  USB interface{ //定义一个USB接口
    Name() string //返回USB名称
    Connecter     //连接的方法
}
type Connecter interface{ //这里的Connecter具备Connect()方法,所以USB中直接嵌入Connecter
    Connect()
}
type PhoneConnecter struct{ //定义手机连接器结构,有一个name变量
    name string
}
func (pc PhoneConnecter)Name() string  { //定义一个receiver是PhoneConnecter结构的Name()方法,返回一个string类型的pc.name
    return pc.name
}
func (pc PhoneConnecter)Connect(){ //定义一个receiver是PhoneConnecter结构的Connect()方法,打印pc.name
    fmt.Println("Connect",pc.name)
}
func Disconnect(usb interface{}){
    switch v := usb.(type){  //这里使用高效简便的type switch方法判断局部变量v的类型
    case PhoneConnecter:
        fmt.Println("Disconnected",v.name)
    default:
        fmt.Println("Unknown device")
    }
}
func main(){
    //var a USB //定义一个USB接口
    a := PhoneConnecter{"PhoneConnecter"}//初始化一个name=PhoneConnecter的手机连接器(具有接口USB属性)
    a.Connect()
    Disconnect(a)
}
Connect PhoneConnecter
Disconnected PhoneConnecter

50.接口转换

可以将拥有超集的接口转换为子集的接口
可以把USB转换为Connecter方法,因为USB还包含了name属性

package main
import (
    "fmt"
)
type  USB interface{ //定义一个USB接口
    Name() string //返回USB名称
    Connecter     //连接的方法
}
type Connecter interface{ //这里的Connecter具备Connect()方法,所以USB中直接嵌入Connecter
    Connect()
}
type PhoneConnecter struct{ //定义手机连接器结构,有一个name变量
    name string
}
func (pc PhoneConnecter)Name() string  { //定义一个receiver是PhoneConnecter结构的Name()方法,返回一个string类型的pc.name
    return pc.name
}
func (pc PhoneConnecter)Connect(){ //定义一个receiver是PhoneConnecter结构的Connect()方法,打印pc.name
    fmt.Println("Connect",pc.name)
}

func main(){
    b := PhoneConnecter{"PhoneConnecter"}//初始化一个name=PhoneConnecter的手机连接器b(天生实现了接口USB接口),因为b具备Name属性和Connect()方法
    b.Connect()
    fmt.Println(b.name)
    var a Connecter
    a=Connecter(b)//强制类型转换,将PhoneConnecter的pc转换为Connecter,connect只有Connect()方法,没有name属性
    a.Connect()
    //fmt.Println(a.name) 这里打印出错,因为Connecter没有name属性
}
Connect PhoneConnecter
PhoneConnecter
Connect PhoneConnecter

将对象赋值给接口时,会发生拷贝,而接口内部存储的是指向这个复制品的指针,既无法修改复制品的状态,也无法获取指针

package main
import (
    "fmt"
)
type  USB interface{ //定义一个USB接口
    Name() string //返回USB名称
    Connecter     //连接的方法
}
type Connecter interface{ //这里的Connecter具备Connect()方法,所以USB中直接嵌入Connecter
    Connect()
}
type PhoneConnecter struct{ //定义手机连接器结构,有一个name变量
    name string
}
func (pc PhoneConnecter)Name() string  { //定义一个receiver是PhoneConnecter结构的Name()方法,返回一个string类型的pc.name
    return pc.name
}
func (pc PhoneConnecter)Connect(){ //定义一个receiver是PhoneConnecter结构的Connect()方法,打印pc.name
    fmt.Println("Connect",pc.name)
}
func main(){
    b := PhoneConnecter{"PhoneConnecter"}//初始化一个name=PhoneConnecter的手机连接器b(天生实现了接口USB接口),因为b具备Name属性和Connect()方法
    var a Connecter
    a=Connecter(b)//强制类型转换,将PhoneConnecter的pc转换为Connecter,connect只有Connect()方法,没有name属性
    a.Connect()
    b.name="pc"
    a.Connect() //这里完全忽视了我们的修改,因为拿到的是一个拷贝
}
Connect PhoneConnecter
Connect PhoneConnecter

只有当接口存储的类型和对象都为nil时,接口才等于nil

package main
import "fmt"
func main(){
    var a interface{} //a=nil
    fmt.Println(a==nil)

    var p *int = nil
    a = p //a指向的对象是nil,但是本身是一个指向int型的指针,不是nil,所以打印false
    fmt.Println(a==nil)
}
true
false

接口调用不会做receiver的自动转换
接口同样支持匿名字段方法
接口也可实现类似OOP中的多态
空接口可以作为任何类型数据的容器

51.反射reflection

反射可大大提高程序的灵活性,使得 interface{} 有更大的发挥余地
反射使用 TypeOf 和 ValueOf 函数从接口中获取目标对象信息
反射会将匿名字段作为独立字段(匿名字段本质)
想要利用反射修改对象状态,前提是 interface.data 是 settable,
即 pointer-interface

通过反射可以“动态”调用方法
定义一个结构,通过反射来打印其信息,并调用方法。

52.并发concurrency

很多人都是冲着 Go 大肆宣扬的高并发而忍不住跃跃欲试,但其实从
源码的解析来看,goroutine 只是由官方实现的超级“线程池”而已。
不过话说回来,每个实例 4-5KB 的栈内存占用和由于实现机制而大幅
减少的创建和销毁开销,是制造 Go 号称的高并发的根本原因。另外,
goroutine 的简单易用,也在语言层面上给予了开发者巨大的便利。

并发不是并行:Concurrency Is Not Parallelism
并发主要由切换时间片来实现“同时”运行,在并行则是直接利用
多核实现多线程的运行,但 Go 可以设置使用核数,以发挥多核计算机
的能力。

Goroutine 奉行通过通信来共享内存,而不是共享内存来通信。

53.Channel

Channel 是 goroutine 沟通的桥梁,大都是阻塞同步的
通过 make 创建,close 关闭
Channel 是引用类型
可以使用 for range 来迭代不断操作 channel
可以设置单向或双向通道
可以设置缓存大小,在未被填满前不会发生阻塞

54.Select

可处理一个或多个 channel 的发送与接收
同时有多个可用的 channel时按随机顺序处理
可用空的 select 来阻塞 main 函数
可设置超时

创建一个 goroutine,与主线程按顺序相互发送信息若干次并打印


有疑问加站长微信联系(非本文作者)

本文来自:51CTO博客

感谢作者:1350368559

查看原文:Go编程基础-学习2

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

750 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传