编程语言
首页 > 编程语言> > Golang 学习之路(一)程序结构

Golang 学习之路(一)程序结构

作者:互联网

程序结构

命名

Go 中的命名规范与 Java 类似,都是必须以一个字母或者下划线开头,不能是数字开头,后面可以接上任意的数字和字母,并且区分大小写。

有 25 个关键字,不能被用于自定义变量名

break 		default 	func 	interface 	select
case 		defer 		go 		map 		struct
chan 		else 		goto 	package 	switch
const 		fallthrough if 		range 		type
continue 	for 		import 	return 		var

此外,还有大约 30 多个预定义的名字,主要对应内建的常量、类型和函数,可以自定义使用这些,但是要在注意使用引起混乱

内建常量: 	true 	false 	iota 	nil
内建类型: 	int 	int8 	int16 	int32 	int64
			uint	uint8 	uint16 	uint32 	uint64 	uintptr
			float32 float64 complex128 		complex64
			bool byte rune string error
内建函数: 	make 	len 	cap 	new 	append 		copy 	close 	delete
			complex 	real 	imag
			panic 		recover

由于 Go 中没有了 Java 中的 privatepublic 关键字来限制方法的访问权限,所以在一个文件中,如果一个名字是大写字母开头的,像函数名,那么它将是导出的,也就是可以被外部的包访问,例如fmt.Printf()可以在引用了fmt包的地方访问 Printf方法

变量

var 声明语句可以创建一个特点类型的变量,然后给变量附加一个名字,并且设置变量的初始值。语法如下

var 变量名字 类型 = 表达式
var s string = "apple" 

其中,变量类型和表达式可以省略掉其中的一个,如果省略了类型,则会根据表达式的内容进行类型推断;如果省略了表达式的值,则会使用零值来初始化。

Go 语言的零值机制可以确保声明的变量都有一个良好定义的值,从而避免很多不必要的麻烦。因此在 Go 语言中不存在未初始化的变量,也就可以在不需要额外代码的情况下判断边界条件的合理性。

例如:

var s string 
fmt.Println(s) 	//输出的是空字符串"",啥都没有,而不是错误或者其他不可预知的行为

也可同时声明多个变量

var j,k,l int		//三个变量都是int
var j,k,l,m = 1,false,"str",0.65	//int, bool, string,float

也可以通过函数返回的多个值进行初始化

var f, err = os.Open(name)

简短变量声明

在函数内部,可以通过 名字 := 表达式 的形式声明变量,变量的类型根据表达式来推断

a := 0.0
start := time.Now()
i, j := 0, 1
resp, err := http.Get(url)

简短变量声明语句中必须至少要声明一个变量,下面的情况将无法编译通过:

f, err := os.Open(infile)
// ...
f, err := os.Create(outfile) 		//会报错

指针

一个指针的值是另一个变量的地址。即指向对应变量在内存中的存储位置。

x := 2
p := &x
fmt.Println(p)			//0xc000054190
fmt.Println(*p)			//2
fmt.Println(x)			//2
*p = 100
fmt.Println(p)			//0xc000054190
fmt.Println(*p)			//100
fmt.Println(x)			//100
fmt.Println(x==*p)		//true

任何指针的零值都是 nil

var p *int					//初始化指针变量,零值为nil
fmt.Println(p) 				//<nil>
fmt.Println(p == nil)		//true

var x, y string
fmt.Println(&x,&y)			//0xc000032bc0 0xc000032bd0 	
							//x,y的零值为"",但是分配了不同的内存地址
fmt.Println(&x == &y,&x == nil, &y == nil)		//false false false
func f() *int {
	y := 1
	return &y
}

fmt.Println(f())			//0xc000054198
fmt.Println(f())			//0xc0000541c0
fmt.Println(f() == f())		//false

对于Go语言,严格意义上来讲,只有一种传递,也就是按值传递(by value)。当一个变量当作参数传递的时候,会创建一个变量的副本,然后传递给函数或者方法,你可以看到这个副本的地址和变量的地址是不一样的。

new 函数

内建的 new 函数也可以来创建变量,通过表达式 new(T) 将创建一个 T 类型的匿名变量,并且初始化零值,然后返回变量地址,返回的指针类型为 *T

p := new(int)
fmt.Println(p)				//0xc000054190
*p = 1000
fmt.Println(*p)				//1000

虽然 new 是 Go 的内建函数,但是并不是 25 个关键字之一,所以可以被用作变量名

每次调用new函数都是返回一个新的变量地址

变量的生命周期

对于在包一级的声明的变量来说,它们的生命周期和整个程序运行的生命周期一致。相比之下,局部变量的生命周期则是动态的:每次从创建局部变量到不再被引用为止,然后可能被回收。函数的参数和返回值都是局部变量。

一个变量的有效周期只取决于是否可达,因此一个局部变量的可能会超出其作用域,同时,局部变量可能在函数返回之后依然存在。

编译器会自动选择是在栈上还是在堆上分配局部变量的存储空间,这个并不是由用var 声明还是用new声明的

var global *int

func a() {
	var x int
	x = 1
	global = &x
}

func b() {
	x := new(int)
	*x = 1
}

对于a() 来说,局部变量x必须分配到堆上,因为在函数a退出后,x依然可以通过包一级的变量找到,也就是说,这个局部变量x从函数a中逃逸了。相反的,在函数b中的局部变量x在函数退出后就可以马上被回收了。编译器可以选择在栈上分配函数b中的x的内存空间,当然也可以选择在堆上分配,然后由 Go 的垃圾回收器GC来回收

赋值

元组赋值

元组赋值允许同时更新多个变量的值。

在赋值之前,右边的所有表达式会先进行求职,然后再统一更新左边的值。

例如,求最大公约数

func gys(x, y int) int {
	for y != 0 {
		x, y = y, x%y
	}
	return x
}
fmt.Printf("最大公约数为%v\n",gys(16,24))		//最大公约数为8

计算斐波那契数列的第N个数

func fib(n int) int {
	x, y := 0, 1
	for i := 0; i < n; i++ {
		x, y = y, x+y
	}
	return x
}

fmt.Printf("斐波那契数列的第%v个数是%v\n",15,fib(15))	//610

标签:学习,变量,int,fmt,程序结构,Golang,var,Println,零值
来源: https://blog.csdn.net/liu_1024_/article/details/93339048