go初学者易错点

1,slice append

[0 0 0 0 0 1 2 3]

[1 2 3 4]

append一定是在长度后追加

type MyInt1 int  新类型

type MyInt2 = int   int别名

slice  [i:j:k]  长度=j-i  容量=k-i   起始索引 i 到 索引j-1

只有slice和chanel可以用cap函数

go打印 %+d 表示打印十进制的符号  比如fmt.Printf("%+d %+d",-5,+5) 输出为-5 +5

闭包引用的外部变量的地址,外部变量地址变了,闭包内引用的变量肯定改变了

type Person struct {

    age int

}

funcmain() {

    person := &Person{28}

    // 1.

    defer fmt.Println(person.age)  // 参数就是 28

    // 2.

    defer func(p *Person) {    // 参数为 Person指针 指向的是 &Person{28}

        fmt.Println(p.age)

    }(person)

    // 3.

    defer func() {

        fmt.Println(person.age)   //闭包 输出 29 person本身改变了

    }()

    person = &Person{29}

}

函数参数为 interface{} 时可以接收任何类型的参数,包括用户自定义类型等,即使是接收指针类型也用 interface{},而不是使用 *interface{}。

永远不要使用一个指针指向一个接口类型,因为它已经是一个指针。

在go中,在if中else if else

if a:= 1; false{

}else{

    fmt.Println(a)    //输出1

}

3,一个函数秒懂defer

funcmain(){

a :=1

b :=2

defercalc("1", a, calc("10", a, b))

a =0

defercalc("2", a, calc("20", a, b))

b =1

}

funccalc(indexstring, a, bint)int{

ret := a + b

fmt.Println(index, a, b, ret)

returnret

}

答案及解析:

10 1 2 3

20 0 2 2

2 0 2 2

1 1 3 4

给一个结构体Stu绑定方法如 func (stu *Stu) Speak()string{} 或 func (stu Stu)Speak()string{},指针*Stu这两个方法都可以调用,但结构体Stu只能调用Stu的方法。

iota 是 golang 语言的常量计数器,只能在常量的表达式中使用。iota 在 const 关键字出现时将被重置为0,const中每新增一行常量声明将使 iota 计数一次。

4,结构体比较

结构体只能比较是否相等,不能比较大小,相同类型的结构体才能够进行比较,结构体是否相同不但与属性类型有关,还与属性顺序相关。

什么是可比较的呢,常见的有 bool、数值型、字符、指针、数组等,像切片、map、函数等是不能比较的。

5,新类型 type Myint int ,Myint是一个新类型,不能互相赋值;别名 type Myint = int,Myint和int一样,可以互相赋值;

6,nil 只可以用作 interface、function、pointer、map、slice 和 channel 的“空值”。

7,init函数

init() 函数是用于程序执行前做包的初始化的函数,比如初始化包里的变量等;

一个包可以出线多个 init() 函数,一个源文件也可以包含多个 init() 函数;

同一个包中多个 init() 函数的执行顺序没有明确定义,但是不同包的init函数是根据包导入的依赖关系决定的(看下图);

init() 函数在代码中不能被显示调用、不能被引用(赋值给函数变量),否则出现编译错误;

一个包被引用多次,如 A import B,C import B,A import C,B 被引用多次,但 B 包只会初始化一次;

引入包,不可出现死循坏。即 A import B,B import A,这种情况编译失败;

8,类型断言

类型选择,类型选择的语法形如:i.(type),其中 i 是接口,type 是固定关键字,需要注意的是,只有接口类型才可以使用类型选择。

9,一个 map 中不存在的值时,返回元素类型的零值

10,闭包引用 函数内部引用外部变量,

11,永远不要使用一个指针指向一个接口类型,因为它已经是一个指针

12,结构体只能调用结构体的方法,指针既可以调用结构体的方法也可以调用指针的方法

13,iota 是 golang 语言的常量计数器,只能在常量的表达式中使用。iota 在 const 关键字出现时将被重置为0,const中每新增一行常量声明将使 iota 计数一次。

14,当且仅当动态值和动态类型都为 nil 时,接口类型值才为 nil。即值为nil类型也为nil。

15,for i,v := range 数组,for i,v := range 切片 不一样 range虽然是值拷贝,但切片是个指针,拷贝的是一个指针,里面的数据指针还是指向同一片内存, 数组就不一样了,数组进行值拷贝,在range的时候就是另一个栈空间了。

16,for range 使用短变量声明(:=)的形式迭代变量时,变量 i、value 在每次循环体中都会被重用,而不是重新声明。

17,多重赋值,多重赋值分为两个步骤,有先后顺序:计算等号左边的索引表达式和取址表达式,接着计算等号右边的表达式;赋值;简单的说就是先确定左边的值(表达式要计算出具体的值),在确定右边的值,然后进行赋值

18,强制类型转换  type Myint int  var a int = 1  var b Myint = Myint(a) 

不可用var b Myint = a.(Myint)  只有接口才使用类型断言

19,自增自减操作。i++ 和 i-- 在 Go 语言中是语句,不是表达式,因此不能赋值给另外的变量。此外没有 ++i 和 --i。

20,select 的用法有点类似 switch 语句,但 select 不会有输入值而且只用于信道操作。select 用于从多个发送或接收信道操作中进行选择,语句会阻塞直到其中有信道可以操作,如果有多个信道可以操作,会随机选择其中一个 case 执行。

21,常量。常量不同于变量的在运行期分配内存,常量通常会被编译器在预处理阶段直接展开,作为指令数据使用,所以常量无法寻址。

22,关于信道

var c chan int // 方式一

c  := make(chan int) // 方式二

使用关键字 chan 创建信道,声明时有类型,表明信道只允许该类型的数据传输。信道的零值为 nil。方式一就声明了 nil 信道。nil 信道没什么作用,既不能发送数据也不能接受数据。方式二使用 make 函数创建了可用的信道 c。

信道在箭头的左边是写数据,在右边是从信道读数据

信道操作默认是阻塞的,往信道里写数据之后当前协程便阻塞,直到其他协程将数据读出。一个协程被信道操作阻塞后,Go 调度器会去调用其他可用的协程,这样程序就不会一直阻塞。信道的这种特性非常有用。

如果缓冲信道是关闭状态但有数据,仍然可以读取数据

rch := make(<-chan int)     只发送信道

sch := make(chan<- int)     只接受信道

使用单向通道主要是可以提高程序的类型安全性,程序不容易出错。

信道为 nil,读写都会阻塞。

23,for range 使用的副本,如果为数组 for range arr arr是原来数组的副本相当于另一个数组,和原来的数组不是一个数组,在循环过程中改变比如arr[0]=1,此时改变的是原数组,和for range arr 这个arr没有任何关系。如果为切片for range slice slice与原来的切片底层数据是一样的,slice包括数据指针,len,cap,数据指针指向的是同一片内存,如果在循环中改变原s切片的len,cap,相当于改变了原切片中的数据指针(cap不够则重新分配内存),len,cap,而for range是拷贝,现有的slice是不会改变的。

24,不能对 nil 的 map 直接赋值,需要使用 make() 初始化。但可以使用 append() 函数对为 nil 的 slice 增加元素。

25,rune 是 int32 的别名一样,byte 是 uint8 的别名,别名类型无序转换,可直接转换。

26,常量是一个简单值的标识符,在程序运行时,不会被修改的量。不像变量,常量未使用是能编译通过的。常量组中如不指定类型和初始化值,则与上一行非空常量右值相同

27,:= 操作符不能用于结构体字段赋值。

28,Go 语言的 switch 语句虽然没有"break",但如果 case 完成程序会默认 break,可以在 case 语句后面加上关键字 fallthrough,这样就会接着走下一个 case 语句(不用匹配后续条件表达式)。

29,函数只能与 nil 比较

30,直接返回的 T{} 不可寻址;不可寻址的结构体不能调用带结构体指针接收者的方法;结构体可以调用指针的方法,但是必须可寻址。

31,从一个基础切片派生出的子切片的长度可能大于基础切片的长度。假设基础切片是 baseSlice,使用操作符 [low,high],有如下规则:0 <= low <= high <= cap(baseSlice),只要上述满足这个关系,下标 low 和 high 都可以大于 len(baseSlice)。

s := make([]int, 3, 9)

fmt.Println(len(s))   // 3

s2 := s[4:8]

fmt.Println(len(s2))     // 4

截取符号 [i:j],如果 j 省略,默认是原切片或者数组的长度,s3 := s[4:]就是错误的 相当于s[4:3]

32,将 Mutex 作为匿名字段时,相关的方法必须使用指针接收者,否则会导致锁机制失效。

33,nil 不是关键字,nil := 123 这样赋值正确,此时nil为变量。

34,defer() 后面的函数如果带参数,会优先计算参数,并将结果存储在栈中,到真正执行 defer() 的时候取出。

35,recover() 必须在 defer() 函数中直接调用才有效

36,goto 不能跳转到其他函数或者内层代码

37,闭包引用(变量指针)简单的说就是一个函数内部可以引用外部变量,

38,在 Go 语言中,双引号用来表示字符串 string,其实质是一个 byte 类型的数组,单引号表示 rune 类型。

39,DeferTest2(1)  执行顺序  首先 r=2 闭包引用 r += 1 即r=3 所以返回3

func DeferTest2(iint) (r int) {

    defer func() {

        r += i

    }()

    return 2

}

40,Go 语言的取反操作是 ^,对数 a 取反,结果为 -(a+1),

41,只能用于函数内部;短变量声明语句中至少要声明一个新的变量;

42,可变函数是指针传递   fun(args...)   var s []int = {1,2.3}  fun(s)

43,类型的 String() 方法。如果类型定义了 String() 方法,使用 Printf()、Print() 、 Println() 、 Sprintf() 等格式化输出时会自动使用 String() 方法。如果这时显式的调用会造成死循环。s.string()

44,关于方法指针接收器用法

一般来说,指针接收器可以使用在:对方法内部的接收器所做的改变应该对调用者可见时。

指针接收器也可以被使用在如下场景:当拷贝一个结构体的代价过于昂贵时。

45,启动一个新的协程时,协程的调用会立即返回。与函数不同,程序控制不会去等待 Go 协程执行完毕。

46,信道接收发送必须成对存在,否则会造成死锁。

47,从一个关闭的信道继续接收值时回返回接受累类型的默认值,如 v,ok : <- ch ch关闭后 v 为0,ok为false

48,select 语句用于在多个发送/接收信道操作中进行选择。select 语句会一直阻塞,直到发送/接收操作准备就绪。如果有多个信道操作准备完毕,select 会随机地选取其中之一执行。该语法与 switch 类似,所不同的是,这里的每个 case 语句都是信道操作。

49,Mutex 用于提供一种加锁机制(Locking Mechanism),可确保在某时刻只有一个协程在临界区运行,以防止出现竞态条件。

50,go通过结构体组合嵌套实现类似面向对象继承。

51,go通过接口来实现面向对象多态。

52,在 Go 语言中,并非在调用延迟函数的时候才确定实参,而是当执行 defer 语句的时候,就会对延迟函数的实参进行求值。

53,高阶函数:接收一个或多个函数作为参数,返回值是一个函数

54,闭包实质是变量引用。闭包=函数+引用环境

55,通过var声明的零值切片可以在append()函数直接使用,无需初始化。

56,切片copy语法 copy(destSlice, srcSlice[]T) 

57,两个切片相加  a=append(b,c...) 第二个切片必须加 ...

58,go中json数字转过来是float64,可以用gob或github.com/vmihailenco/msgpack代替json 

59,闭包引用中的变量相当于C语言函数中的static变量一直有效,位于静态存储区,闭包其实并不复杂,只要牢记闭包=函数+引用环境

60,recover()必须搭配defer使用,defer一定要在可能引发panic的语句之前定义。

61,结构体和指针都可以调用结构体或指针绑定的方法

62,匿名字段的说法并不代表没有字段名,而是默认会采用类型名作为字段名,结构体要求字段名称必须唯一,因此一个结构体中同种类型的匿名字段只能有一个。 如果有一个匿名字段是string 相当于string string 变量名为string 类型为string

63,结构体中字段大写开头表示可公开访问,小写表示私有(仅在定义当前结构体的包中可访问)。

64,接口中的方法实现如果是指针方法实现 那么改接口只能赋值对应类型的指针不能为结构体,反之则指针则可以隐式转换。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,245评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,749评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,960评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,575评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,668评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,670评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,664评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,422评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,864评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,178评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,340评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,015评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,646评论 3 323
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,265评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,494评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,261评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,206评论 2 352