go程序结构

1、命名规则

  • 名称的开头是字母或者下划线,后面可以跟任意数量的字符、数字或者下划线。

  • 区分大小写,hello和Hello是不同的名称

  • 实体第一个字母的大小写决定其可见性是否跨包。

  • 包名本身总是由小写字母组成

  • 名称本身没有长度限制,倾向使用短名称,并且驼峰式风格。

2、 变量(var)

声明通用格式var name type = expression

  • 类型(type)和表达式(expression)可以省略一个,但是不可以都省略。

  • 类型(type)省略:类型由表达式决定

  • 表达式(expression)省略:其初始值对应着类型的零值。

// 可以声明一个变量列表,忽略类型允许声明多个不同类型的变量
var i, j, k int  // int, int, int
var b, f, s = true, 2.3, "four" // bool, float64, string

go的零值机制保障所有的变量都是良好定义的,不存在未初始化变量。

类型 零值
数字 0
布尔值 false
字符串 空字符串("")
接口和引用类型(slice、指针、map、通道、函数) nil
复合类型(数组或结构体) 所有元素或者成员的零值

短变量声明通用格式name := expression

  • 局部变量的声明和初始化中主要使用短声明

  • :=表示声明,单纯的=表示赋值。 i, j = j, i // 表示交换i和j的值

  • 短变量声明最少声明一个新变量,否则代码无法编译通过。

  • 多变量声明中的已声明变量,短声明的行为等同于赋值。

指针&x

  • 变量是存储值的地方,指针的值是一个变量的地址。

  • 指针可进行比较。指针相等的情况:

    • 指向同一个变量

    • 都是nil

new函数

  • new(T)创建一个T类型变量,初始化T类型的零值,并返回其地址。

  • 每一次调用new返回具有唯一地址的不同变量

i := new(int)
j := new(int)
fmt.Println(i == j) // false

变量的生命周期

  • 包级别变量的生命周期是整个程序的执行时间

  • 局部变量有一个动态的生命周期

  • 垃圾回收期会追溯局部变量的源头,判断其路径是否可达,来进行回收

  • 每一次变量逃逸都需要一次额外的内存分配过程。下面代码变量x使用堆空间。

var global *int
func f() {
	// 变量x从函数f中逃逸
	// 虽然x被声明为局部变量,但f函数返回后还可以从global访问
	var x int
	x = 1
	global = &x
}

3、赋值

多重赋值

  • 用于交换值x, y = y, x

  • 函数返回,左边变量数量需要与返回的数量保持一致

    函数返回ok的bool类型变量的几种情况:

    v, ok = m[key]  //map查询
    v, ok = x.(T)   //类型断言
    v, ok = <-ch    //通道接收
    

4、类型声明

type声明定义一个新的命名类型。

每个类型T,可以通过T(x)将值x转换为类型T。

可以转换的条件是:底层类型相同或者指向相同底层类型变量的未命名指针类型。

命名类型的值可以与其相同类型的值或者底层类型相同的未命名类型的值比较。

// 即使A和B底层类型相同,它们依旧是不同类型
type A float64
type B float64
var a A
var b B
fmt.Println(a == 0) // true
fmt.Println(b >= 0) // true
fmt.Println(a == b) // 编译错误,类型不匹配

5、包和文件

  • 变量在包外面的可见性通过首字母是否大写来判断。

初始化

  • 包的初始化按照在程序中导入的顺序来进行,自下向上,依赖顺序优先。

    包p导入了包q,包q会先进行初始化

  • init函数不能被调用和被引用。在包初始化时自动运行。

作用域

  • 程序可以包含多个同名的声明,前提是它们在不同的词法块中

  • 内层和外层都存在相同声明,内层声明将覆盖外层声明

  • 编译器查找名字引用时,将自内向外查找。若未找到会报错。

//for循环会创建隐式的词法块
x := "hello"
for _, x := range x {
	x := x + 'A' - 'a'
	fmt.Printf("%c", x) //输出hello
}
if x := f(); x == 0 {
	fmt.Println(x)
} else if y := g(x); x == y {
	fmt.Println(x, y) //编译成功,第二个if语句嵌套在第一个中,所以x在此处可见
} else {
	fmt.Println(x, y)
}
fmt.Println(x, y) //编译错误,x与y不可见
var cwd string
func init() {
	cwd, err := os.Getwd() // 注意:错误。cwd和err在内部未声明,所以会将他们声明为局部变量
	//var err error        // 该注释内容为正确写法
	//cwd, err = os.Getwd()
	if err != nil {
		fmt.Println(err)
		return
	}
}
posted @ 2024-06-02 08:20  卖油条的大叔  阅读(54)  评论(0)    收藏  举报