李守中

Golang 学习笔记 1 代码风格

Table of Contents

1 项目文件夹结构

go 项目文件夹至少包括 3 个文件夹。针对个人开发:

  1. /bin 存放编译生成的二进制文件;
  2. /pkg 存放编译后生成的归档文件;
  3. /src 存放源代码:
    1. 网站域名 a:
      1. 作者 1:
        1. 项目 1:
          1. 模块 1
          2. 模块 2
          3. 模块 3
          4. ...
        2. 项目 2: ...
        3. 项目 3: ...
        4. ...
      2. 作者 2: ...
      3. 作者 3: ...
      4. ...
    2. 网站域名 b: ...
    3. 网站域名 c: ...
    4. ....

2 名称和声明

命名规则:

  • 名字以大写字母开头,则在包外可访问;
  • 名字以小写字母开头,不可在包外访问。

声明 给一个实体命名,然后设定其属性:

  • 一个实体在函数内声明,那么它只在函数内部有效;
  • 一个实体在函数外声明,那么它对包里的所有文件可见;

主要的声明关键字: 变量 var ,常量 const ,类型 type 和函数 func 。一个文件夹只能含有一个包,包名是每个 .go 文件的开头。

3 变量声明

变量声明以后会被初始化为各个类型的零值:

  • 数字 - 0
  • 字符串 - ""
  • boolean - false
  • slice, map, 指针, 通道, 函数 - nil

var name type = expressiontypeexpression 可以省略一个。主要用来给初始化表达式的类型与声明类型不同的变量赋值,或者用于初始值不重要以及后面才对变量赋值的情况。

name := expressionname 的类型由 expression 的类型决定。

// main 包和 func main() {...} 函数只有一个,是程序执行的入口。
// 一个文件夹下只能有一个包。
package main

import "fmt"

const boilingC = 100     // main 包中,包级别的声明

func main(){
    s := ""              // 常在包内部使用,变量重要
    var s string         // 常在包内部使用,变量不重要,以后赋值
    var s = ""           // 很少用,除非声明多个变量
    var s string = ""    // 类型一致下多余,类型不一致下必须

    i, j := 0, 1         // 多变量声明和初始化
    i, j = j, i          // 交换两个变量的值
}

短变量声明不需要声明所有左边的变量。 对于第一个 err 变量,代码行为是 声明并赋值 ;对于第二个 err 变量,代码行为是 赋值

in, err := os.Open(infile)
//...
out, err := os.Create(outfile)

短变量最少需要声明一个变量,否则编译无法通过:

f, err := os.Open(infile)
//...
f, err := os.Create(outfile) // 编译错误,没有新的变量
f, err = os.Create(outfile)  // 编译通过

3.1 指针声明

指针的值是一个变量的地址,指针指示值保存的位置。不是所有的值都有地址,但是所有的变量都有。

x := 3
p := &x   // p 类型为 *int
*p = 2    // x = 2

指针是可以比较的,两个指针,当且仅当,指向同一个变量,或者两者都是 nil 的情况下相等。

fmt.Println(&x == &x, &x == &y, &x == nil) // `true false false`

3.2 new 函数

new 函数可以创建变量, new(T) 创建一个未命名的 T 类变量,初始化为其 空值 ,并且 返回其地址 。很少用。

3.3 赋值与多重赋值

最简单的形式是 =:

x = 1                       // 有名称的变量
*p = true                   // 间接变量
person.name = "name"        // 结构体成员
count[x] = count[x] * scale // 数组或 slice 或 map 的元组

进阶形式:

count[x] *= scale

v := 1
v++
v--

多重赋值允许多个变量一次性被赋值:

x, y = y, x                     // 交换两个变量的值
j, k, l = 1, 2, 3               // 变量赋值更紧凑
f, err = os.Open("foo.text")    // 调用返回两个值的函数
v, ok = m[key]                  // map 查询
v, ok = x.(T)                   // 类型断言
v, ok = <-ch                    // 通道接收

可赋值性: 指等号左右两边的变量为同一类型才可以进行赋值。类似的, ==!= 必须要两边同一类型(可以双向赋值)才能进行比较。

4 声明新类型

type name underlying-type 定义一个新的类型:

type var1 float64
type var2 float64

const (
    a var1 = 1.1
    b var2 = 2.2
)

func fun(){
    var c var1;
    c = b       // 报错,类型不一样
    c = var1(b) // 必须要使用类型转换
}

尽管 varvar2 有相同的底层类型,但是他们依旧是两个不同的类型: 不能使用算数表达式进行合并。

对于每个类型 T ,都有一个对应的类型转换操作 T(x) 可以将 x 转换为 T 类型。如果两个类型具有相同的底层类型,或二者都是指向相同底层类型变量的未命名的指针类型,则可以相互转换。

5 运算符优先级

// 运算符优先级排序
*   /   %   <<   >>   &   &^
+   -   |   ^
==  !=  <   <=   >    >=
&&
||

其中:

  • ^ 作为二元运算符表示按位异或,作为一元运算符表示操作数逐位取反;
  • &^ 表示异或;
  • x<<nx>>n 中, n 必须为无符号类型,运算结果向下取整:
    • 左移或右移用 0 补右边位,
    • 符号数右移用符号位补位。


Last Update: 2023-05-18 Thu 09:15

Contact: [email protected]     Generated by: Emacs 27.1 (Org mode 9.3)

若正文中无特殊说明,本站内容遵循: 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议