一、基础
1、
需要注意的是,go在声明变量的时候将变量的类型放到变量的名称之后,原因是为了避免像c语言那样含糊不清的声明形式,
2、
当一个变量被声明之后,系统自动赋予它该类型的零值:int 为 0,float 为 0.0,bool 为 false,string 为空字符串,指针为 nil。记住,所有的内存在 Go 中都是经过初始化的。
3、
变量的作用域:
如果变量在函数外部声明,那么这个变量就是全局变量
如果变量在函数内部声明,那么这个变量就是局部变量
如果全局变量和局部变量的名字相同,那么在函数内部会执行局部变量,而不是全局变量
4、
变量可以在编译之前就被赋值,赋值给变量使用运算符= ,当然也可以在运行时对变量进行赋值操作
a=15
b=false
5、声明与赋值(初始化)语句也可以结合起来
6、变量的类型也可以自动运行时实现自动推断,这种写法主要用于声明包级别的全局变量
var (
HOME= os.Getenv(“HOME”)
USER = os.Getenv(“USER”)
GOROOT= os.Getenv(“GOROOT”)
)
7、当声明局部变量的时候,应使用间断语声明语法:=
a := 1
package main import "fmt" //轻松的声明为指针 var a,b *int //nil //第一种声明方式 var a1 int //0 var b1 bool //false var str string //空 //第二种声明方式 var ( a2 int b2 bool str2 string ) //初始化方式的两种方法,方法一 var a3=15 var b3=false var str3="hello go" //第二种方式 var ( a4=15 b4=false str4="hellogo" ) func main() { fmt.Println(a,b) fmt.Println(a1,b1,str) fmt.Println(str) fmt.Println(a2,b2,str2) }
二、值类型和应用类型
1、
所有像 int、float、bool 和 string 这些基本类型都属于值类型,使用这些类型的变量直接指向存在内存中的值 ,值类型的变量的值存储在栈中
2、另外像数组和结构这些复合类型也是值类型
3、使用等号=将一个变量的值赋值给另一个变量的时候如j=i,实际上就是在内存中将i的值进行了拷贝
4、内存地址会根据机器的不同而有所不同,甚至相同的程序在不同的机器上执行后也会有不同的内存地址。因为每台机器可能有不同的存储器布局,并且位置分配也可能不同
5、在go语言中,指针属于引用类型,其他的引用类型还包括slices,mao,channel。被应用的变量会存储在堆中,以便进行垃圾回收
三、打印
如果是使用"Print"或"Println"函数的话,甚至不需要格式化字符串。这些函数会针对数据类型 自动作转换。"Print"函数默认将每个参数以"%v"格式输出,"Println"函数则是在"Print"函数 的输出基础上增加一个换行。一下两种输出方式和前面的输出结果是一致的。
如果要用"Printf"或"Print"函数输出似有的结构类型,之需要为该结构实现一个"String()"方法, 返回相应的字符串就可以了。打印函数会先检测该类型是否实现了"String()"方法,如果实现了则以 该方法返回字符串作为输出。
函数 fmt.Sprintf
与 Printf
的作用是完全相同的,不过前者将格式化后的字符串以返回值的形式返回给调用者,因此你可以在程序中使用包含变量的字符串
函数 fmt.Print
和 fmt.Println
会自动使用格式化标识符 %v
对字符串进行格式化,两者都会在每个参数之间自动增加空格,而后者还会在字符串的最后加上一个换行符,%s
代表字符串标识符、%v
代表使用类型的默认输出格式的标识符
四、变量的简短形式
1、你声明了一个局部变量却没有在相同的代码块中使用它,同样会得到编译错误,但是全局变量是允许声明但不使用
2、
同一类型的多个变量可以声明在同一行,(这是将类型写在标识符后面的一个重要原因)如:
var a, b, c in
3、
多变量可以在同一行进行赋值,如:
a, b, c = 5, 7, "abc"
上面这行假设了变量 a,b 和 c 都已经被声明,否则的话应该这样使用:
a, b, c := 5, 7, "abc"
右边的这些值以相同的顺序赋值给左边的变量,所以 a 的值是 5
, b 的值是 7
,c 的值是 "abc"
。
这被称为 并行 或 同时 赋值。
如果你想要交换两个变量的值,则可以简单地使用 a, b = b, a
。
(在 Go 语言中,这样省去了使用交换函数的必要)
空白标识符 _
也被用于抛弃值,如值 5
在:_, b = 5, 7
中被抛弃。
_
实际上是一个只写变量,你不能得到它的值。这样做是因为 Go 语言中你必须使用所有被声明的变量,但有时你并不需要使用从一个函数得到的所有返回值。
并行赋值也被用于当一个函数返回多个返回值时,比如这里的 val
和错误 err
是通过调用 Func1
函数同时得到:val, err = Func1(var1)
。
五、init函数
变量除了可以在全局声明中初始化,也可以在 init 函数中初始化。这是一类非常特殊的函数,它不能够被人为调用,而是在每个包完成初始化后自动执行,并且执行优先级比 main 函数高。
每一个源文件都可以包含一个或多个 init 函数。初始化总是以单线程执行,并且按照包的依赖关系顺序执行。
一个可能的用途是在开始执行程序之前对数据进行检验或修复,以保证程序状态的正确性
这里的init初始化和python的__init__类似
练习 推断以下程序的输出,并解释你的答案,然后编译并执行它们。 练习 4.1 local_scope.go: package main var a = "G" func main() { n() m() n() } func n() { print(a) } func m() { a := "O" print(a) } 练习 4.2 global_scope.go: package main var a = "G" func main() { n() m() n() } func n() { print(a) } func m() { a = "O" print(a) } 练习 4.3 function_calls_function.go package main var a string func main() { a = "G" print(a) f1() } func f1() { a := "O" print(a) f2() } func f2() { print(a) }
package main var a string func main(){ a="G" print(a) f1() } func f1(){ a:="o" print(a) f2() } func f2(){ print(a) } //GOG