Thinking_Out_Loud

《Go程序设计语言》读书笔记#1

2018-09-05

第二章 程序结构

< P28 >

Go中的Predeclared identifiers如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Types:
bool byte complex64 complex128 error float32 float64
int int8 int16 int32 int64 rune string
uint uint8 uint16 uint32 uint64 uintptr

Constants:
true false iota

Zero value:
nil

Functions:
append cap close complex copy delete imag len
make new panic print println real recover

这里面的关键字都是不保留的,可以用作我们的自定变量名,当然这是强烈不推荐的。除非已经被命名困难症逼到了绝境。

另外,变量名长度是不作限定的(the larger the scope of a name, the longer and more meanningful it should be),一个全局变量的名字应该比一个局部变量更易见名知义(所以长点也没关系)。

< P31 >

  • :=(the short variable declaration)是用作声明的,而不是像=一样用作赋值;
  • :=左边至少要存在一个未声明的变量;

< P35 >

如果两个变量的类型不承载任何信息,根据编译器的实现,指针地址可能相同,例如struct{}[0]int

1
2
3
var t1 struct{}
var t2 struct{}
fmt.Printf("%t\n", &t1 == &t2) //true t1,t2为[0]int时同理

< P36 >

  • 用生命周期长的指针指向生命周期短的变量会阻碍对该变量的GC;
  • 变量被分配到堆或栈与否不由声明方式决定,如varnew;(mark一下,之后再拓展一篇,如果还有机会看见这个mark)

< P39 >

显式类型转换T(x)是一种转换(conversion),不是函数调用;

< P41 >

首先看代码:

1
2
3
4
5
6
7
8
9
10
11
type T float64
var x T

// 会隐式调用T的String方法(如果有)
fmt.Printf("%v",x)
fmt.Printf("%s",x)
fmt.Println(x)

// 不会调用
fmt.Printf("%g",x)
fmt.Println(float64(x))

那么我们在给T实现String()且需要打印自身时,要注意避免无穷递归调用。

< P46 >

  • 变量的作用域与生命周期不相等,作用域是编译时属性(compile-time property),而生命周期是运行时属性(run-time porperty);
  • 有或没有显式地用花括号界定的作用域都可以笼统地归纳为lexical block;例如包含整个源码的universe block,每个package、文件、forifswitch/selectswitch/select中的每个case

    1
    2
    3
    4
    5
    6
    7
    func main(){
    x := "hello"
    for _ , x := range x{ // for statement中有隐式lexical block
    x := x +'A'-'a' // {}中的显式lexical block
    fmt.Printf("%c",x) // 正常输出"HELLO"
    }
    }
  • 导入的包的作用域是file-level的,所以每个文件都要单独导入,即使是同一个包下;

  • Control-flow label(用于breakcontinuegoto)的作用域是整个函数;
  • 编译器会从最内的lexical blockuniverse block查找变量的声明;所以最内部变量可以shadow(又或称屏蔽/hide)外部同名变量;

< P49 >

在使用:=时要注意作用域;例如,如果要在函数内更新package-level变量,使用:=会重新声明一个同名局部变量;

一段闲扯

!!距离拖延症发作过去了03天!!

从第二章开始的内容已经比第一章多了,不过想想,这也是肯定的。按照这个劲头,似乎半个月就能把这个系列整理完。另外hexo是真的好用,都要治好我多年的拖延症了。