入门

1. hello word

  • go是编译型语言,会编译成机器原生的二进制指令,不需要其他依赖包都可以运行
  • go原生支持Unicode,可以处理所有国家的语言
  • 同一个行中有多个语句和声明,需要加分号
  • 特定符号后面的换行符会被转换成分号
  • go对代码格式的要求很严格,可以用gofmt工具格式化代码
  • goimports工具(golang.org/x/tools/cmd/goimports)可以按需管理导入的声明的插入与删除

2. 命令行参数

  • os包提供一些函数与变量与系统打交道。
  • os.Args供程序访问命令行参数。
  • 只有i++或i—,这是个语句,不是表达式。
  • 在循环里尽量避免赋值操作,因为数据量大时赋值会造成大量的垃圾,加重垃圾回收的负担。

3. 找出重复的行

  • 可以通过bufio包来高效处理输入输出,包括文件的处理。

  • 用fmt.Printf()格式化数据,用于格式化的转义字符(verb) | verb | 描述 | | —- | —- | | %d | 十进制整数 | | %x/%o/%b | 16进制/8进制/2进制 | | %f/%g/%e | 浮点数,精度不同 | | %t | bool | | %c | 字符 | | %s | 字符串 | | %q | 带引号的字符串或字符 | | %v | 任何值 | | %T | 任何值的类型 | | %% | %本身 |

4. GIF动画

  • import包的时候,可以是多段路径,然后使用最后一个路径来使用。
  • 常量只能是数字/字符串/布尔值。

5. 获取一个URL

  • os.Exit(1)会在程序退出时返回状态码1。
  • io.Copy()可以减少缓冲的使用,ioutil会使用缓冲。

6. 获取多个URL

  • ioutil.Discard,输出流,丢弃数据。

7. web服务器

  • 函数返回的err放在函数的一行,可以缩小err变量的作用域。

8. 其他

  • switch从上往下推演,执行第一个匹配上的,就结束,如果需要继续执行,需要用到fallthrough,default语句可以放到任何地方。
  • type关键字给已有类型命名。
  • go指针不支持运算

程序结构

1. 名称

  • 关键字
    1. break default func interface select
    2. case defer go map struct chan else
    3. goto package switch const fallthrough
    4. if range type continue for import
    5. return var
  • 常量
    1. true false iota nil
  • 类型
    1. int int8 int16 int32 int64
    2. uint uint8 uint16 uint32 uint64 uintptr
    3. float32 float64 complex128 complex64
    4. bool byte rune string error
  • 函数
    make len cap new append copy close delete
    complex real imag panic recover

  • 一些注意点

    • 包名由小写字母组成
    • 公有和私有的区别在于第一个字母是否大写

2. 声明

  • 定义
    声明是给程序实体命名,并设定其部分或全部属性。

3. 变量

  • 通用格式
    1. var name type = expression


类型和表达式可以省略一个,类型省略类型则由表达式定;表达式省略,初始值就是零值,对于复合类型,零值就是所有元素的零值。对于接口和引用类型(slice,指针,map,channel,func)的零值是nil.

  • 初始化时间
    包级别的初始化在main之前,局部变量在函数执行时。

  • 短变量声明

    1. name:=expression


类型由表达式决定。

  • :=表示声明,=表示赋值。
  • 短变量声明至少声明一个新变量。

    • 指针
  • 指针是一个变量的地址,不是所有值都有地址,但所有变量都有。

  • 指针类型的零值是nil.
  • 函数返回局部变量的地址是安全的,在函数执行完后,如果指针还被占用,就不会被回收。
  • flag.Parse()函数在出错后,会调用os.Exit(2)来结束程序。

    • new函数
  • 该函数返回一个指针。

  • 两个变量的类型不携带任何信息且是零值,如struct{}或[0]int,当前实现里,具有相同的零值。

    • 生命周期
  • 生命周期是程序执行过程变量存在的时间段。包级别的变量的生命周期是整个程序的执行时间。局部变量由一个动态的生命周期,直到它变得不可访问。

  • 变量的生命周期是通过它是否可达来确定的。
  • 逃逸:局部变量被其他地方使用,比如在函数中声明一个局部变量,但将这个变量的地址返回出来了,就说这个变量逃逸了,这个变量就使用堆空间,由编译器决定。

4. 赋值

  • 多重赋值
    多个变量一次性被赋值,在实际更新变量前,右边的所有表达式被推演。

  • 可赋值性
    类型必须精准匹配,nil可以赋值给任何接口变量或引用类型。

5. 类型声明

  • type声明定义一个新的命名类型。
  • 对于每个类型T,都有T(x),将x装换为类型T.
  • 浮点数转化为整数会丢失小数部分。
  • 字符串转换成字节会分配一份字符串的数据副本。

6. 包和文件

  • 包导入声明可以给包一个别名。

  • 包初始化

    • 包的初始化由包级别的变量开始。按照声明的顺序初始化。
    • 一个变量依赖另一个表达式,按照依赖顺序初始化。
    • init函数不能被调用和被引用。
    • 每次初始化一个包,main包最后初始化。

7. 作用域

  • 作用域与生命周期

    • 声明的作用域是声明在程序文本中出现的区域,是一个编译时的属性。
    • 变量的生命周期是变量在程序中存在的时间,是一个运行时属性。
  • 语法块
    由大括号括起来的语句

  • 词法块
    没有显示包含在大括号里的声明代码

  • 全局块
    包含全部源代码的词法块(内置类型等)

  • 内层声明将覆盖外层声明

  • 隐式的词法块

if和switch会创建隐式的词法块,如果使用了if else if的语句,则后面的if是嵌套在前面的if中,前面if中声明的变量在后面的if中可见。switch语句中,条件对应一个块,每个case对应一个块。

  • 短变量依赖一个明确的作用域

如果在函数中使用一个短变量声明,不管这个函数外是否有同名的全局变量,只要这个变量没有声明就会把它声明为局部变量。

基本数据

数据类型分为四类:

  • 基础类型
  • 聚合类型
  • 引用类型
  • 接口类型