变量

使用var关键词一次定义多个变量,变量名在前,类型在后,声明时不初始化会默认初始化为二进制0值,如果提供初始化值,可以省略类型,由编译器推断。可以多行变量定义

var(
	x,y int
	a,s=100,"abc"
)

简短模式

func main() {
	x := 100 
	a, s := 1, "abc" 
- 
  • 定义变量,同时显式初始化。
  • 不能提供数据类型。
  • 只能用在函数内部。 简短定义在函数多返回值,以及 if/for/switch 等语句中定义局部变量非常方便。

    退化赋值

    同一作用域下赋值的多个变量中至少有一个新变量时,不生成新的旧变量

    多变量赋值

    首先计算所有右值再依次赋值

    x, y := 1, 2 
    x, y = y+3, x+2
    

    未使用错误

    在go中未使用的局部变量会被认为是错误

    变量命名建议

  • 以字母或下画线开始,由多个字母、数字和下画线组合而成。
  • 区分大小写。
  • 使用驼峰(camel case)拼写格式
  • 局部变量优先使用短名。
  • 不要使用保留关键字。
  • 不建议使用与预定义常量、类型、内置函数相同的名字。
  • 专有名词通常会全部大写,例如 escapeHTML。
  • 尽管 Go 支持用汉字等 Unicode 字符命名,但从编程习惯上来说,这并不是好选择
  • 符号名字首字母大小写决定了其作用域。首字母大写的为导出成员,可被包外引用,而 小写则仅能在包内使用。
  • Go源代码中有大量单字母、单个词或缩写命名的简短命名变量,通过保持一致性来维持可读性。
    • i  index 
    • k  key
    • v  value
    • e elem
    • r  range
    • t  time
    • b  byte

      空标识符

      和python类似的go中也有个 “ _ ” 的特殊成员,用于忽略占位符使用,临时规避未使用变量和导入包的错误检查

      常量

      使用const定义常量值,不支持C++中的数字类型后缀,

  • 不使用的常量不会编译错误
  • 常量值可以使用被编译器能计算的结果,如unsafe.Sizeof, len, cap等方法
  • 在常量组中如果不指定类型和值,则与上一行中的相同
    const(
      x unint16 =120
      y
      s ="abc"
      z
    )
    

    枚举与iota

  • go 中没有明确定义enum,可以使用iota标识符实现自增常量实现枚举类型
  • 可以使用空标识符占位
  • 在多常量定义中使用多个iota,各自单独计数,要求每行的列数相同
  • 中断iota自增,必须显式恢复,且后续自增值按行顺序递增,而非按上一个取值递增
  • 默认类型为int,可以显式指定类型
  • 建议使用自定义类型实现用途明确的枚举类型

    基本类型

    ![[../images/Pasted image 20220919103451.png]]![[../images/Pasted image 20220919103502.png]]

  • 标准库 math 定义了各数字类型的取值范围
  • 标准库 strconv 可在不同进制(字符串)间转换。
  • a, _ := strconv.ParseInt("1100100", 2, 32

    别名

    在官方的语言规范中,专门提到两个别名。

    byte alias for uint8 
    rune alias for int32 
    

    别名类型无须转换,可直接赋值。

    引用类型

    特指slice,map,channel,必须使用make函数而非new,因为new不关心内部构造和初始化方法,仅仅按照类型分配初始化的空间,因此new map是无法正常工作的。make会被编译器转换为目标i类型专用的创建函数。也可以使用初始化表达式

    类型转换

    go中禁止大部分隐式类型转换

  • 不能将非bool类型当作bool用
  • 如果转换的目标是指针,单向通道,无返回值的函数,必须使用括号

自定义类型

使用关键字type基于现有基础类型(包括结构体和函数)定义自定义类型 。 即便指定了基础类型,也只表明它们有相同底层数据结构,两者间不存在任何关系,属 完全不同的两种类型。除操作符外,自定义类型不会继承基础类型的其他信息(包括方 法)。不能视作别名,不能隐式转换,不能直接用于比较表达式。

未命名类型

与有明确标识符的 bool、int、string 等类型相比,数组、切片、字典、通道等类型与具 体元素类型或长度等属性有关,故称作未命名类型(unnamed type)。当然,可用 type 为其提供具体名称,将其改变为命名类型(named type)

表达式

流程控制

if else

  • 所有流程控制语句都可以在头部放一行初始化语句,这个语句编译之后会变成代码块里的隐式代码块
  • if else多个嵌套,作用域嵌套,高层无法访问低层
  • if的快乐路径原则
    • 首先判断错误,如果错误,快速返回
    • 所有错误路径都判断错误之后,剩下的就是成功路径,所以说成功逻辑不放在if中
    • 成功逻辑在最后一句

      switch

      ```go switch{ case: case: default:

  • ```
  • 条件表达式不要求为整型
  • case不用break,不会fallthrough
  • 使用没有条件的switch比并列的if-else更清晰
  • 可以显式使用fallthrough
  • 惰性求值:
    • 满足条件直接结束,剩下的case语句都不执行
    • fallthrough之后,当前的case剩下的都不执行
    • 从上到下,从左到右

      for

  • 没有while,只有一个条件判断语句的时候,相当于while
  • 三个语句省略的时候不能不加分号

break,goto和continue

  • 跳出一层循环和直接进入下一次循环
  • go语言支持转移语句,break labelgoto label跳转到指定的循环层,goto的意义或许只是语义更加清晰

课堂练习

对于字符串而言,切片返回的字符数组切片,但是下标访问的确是字节数组

内置函数

切片x[low,high,max],len=high-low,cap=max-low len cap append