Golang学习(三)基本语法[变量、常量、类型、类型转换]
变量声明
Go语言中有四类标记:标识符(identifiers)、关键字(keywords)、运算符(operators)标点符号(punctuation)以及字面量(literals)。Go语言变量标识符由字母、数字、下画线组成,其中首字符不能为数字,同一字母的大小写在Go语言中代表不同标识。在Go语言中,命名标识符时,通常选择英文的52个大小写字母以及数字0~9和下画线来组合成合适的标识符。另外,Go语言中关键字(如下图)是保留字,不能作为变量标识符。
■ 变量是一段可以包含指定类型值的存储。
■ 如果没有给变量赋值,它将包含其类型的零值。零值的示例包括对int或float64变量来说是0,对string变量来说是"",布尔变量的零值是false。
■ 你可以使用:=短变量声明来声明一个变量,并同时为其赋值。
■ 如果变量、函数或类型的名称以大写字母开头,则只能从其他包中的代码访问它们。
■ 函数内一定要使用全部声明的变量,若存在未使用的变量,则代码将编译失败。因此可以将该未使用的变量改为空白标识符_或者干脆注释掉。但未使用的全局变量是没问题的,没 有这个限制。
1.使用var关键字声明
形式1:var a, b, c bool
形式2:var s1, s2 string = "hello", "world"
形式3:var v1 int = 1
形式4:var v2 = 2
形式5:var (
name = "soaring"
age = 1
gender
)
使用var关键字声明的变量,可以放在函数内,也可以放在包内,可以使用 var()集中定义变量
package main import "fmt" var ( aa = 11 bb = 33 ) func veriablVar() { var name string //声明一个未赋值的变量 var age int = 1 //声明一个赋值变量 var gender = "男" // 声明一个不加类型的变量 var mobile,address = 1311111111, "北京市昌平区上地软件园" //一次声明多个变量 fmt.Printf("%q %d %s %d %s", name, age, gender, mobile, address) } func main() { veriablVar() println(aa, bb) }
2.使用简式声明“:”声明变量(推荐使用)
形式1:a := 1
形式2:b, c, d := true, false, "soaring"
注意,使用“:”声明的变量,只能在函数内部使用
package main import "fmt" func veriableShorter() { a := 1 //声明并赋值 b,c := "soaring", true //声明多个变量并赋值 c = false //修改变量值 fmt.Println(a, b ,c) } func main() { veriableShorter() }
简式声明可能常常出现在函数内部。但在某些上下文中,例如“if”,“for”或“switch”语句的初始化程序中也可以使用,它们可用于声明本地临时变量。
简式声明虽然一般用在函数内,但要注意的是:全局变量和简式声明的变量尽量不要同名,否则很容易产生偶然的变量隐藏(Accidental Variable Shadowing)。
package main import ( "fmt" ) var x int = 10 //声明一个包内全局变量 func main() { x := 1 //这里全局变量x和简式变量会出现变量隐藏,全局变量在此失效 fmt.Println(x) //简式变量在该层block生效,输出 1 { fmt.Println(x) //输出 1 x := 2 fmt.Println(x) //输出 2 } fmt.Println(x) //输出 1 }
上面代码的输出一方面验证了变量隐藏这个现象,另一方面也展现了Go语言中的作用域问题。其实所谓变量隐藏就是因为变量作用域不同导致的现象。在一个作用域中,声明一个标识符并使用时,需要注意它的使用范围即作用域。下面是有关Go语言中作用域的规则:
■ 在Go语言中,在顶层声明的常量、类型、变量或函数的标识符的范围是包块。
■ 导入包名称范围是包含导入声明的文件的文件块。
■ 方法接收器、函数参数或结果变量的标识符的范围是函数体。
■ 在函数内声明的常量或变量标识符的范围从声明语句的末尾开始,到最内层包含块的末尾结束。
■ 在函数内声明的类型标识符的范围从标识符开始,到最内层包含块的末尾结束。
■ 块中声明的标识符可以在内部块中重新声明。如果想要交换两个变量的值,则可以简单地使用:a, b = b, a
另外,在Go语言中,如果导入的包未使用,就不能通过编译。如果不直接使用包里的函数,而只是调用包中的init()函数,或者调试代码时去掉了对某些包的功能使用,可以添加一个下画线标识符“_”来作为这个包的名字,从而避免编译失败。在import语句中,下画线标识符用于表示导入,但不会在包中使用。
在Go语言中,指针属于引用类型,其他的引用类型还包括切片、字典和通道,如果传递引用类型参数或者赋值给引用类型变量,原始数据有改动时它们也会发生变化。注意,Go语言中的数组是值类型,因此向函数中传递数组时,函数会得到原始数组数据的一份副本。如果打算更新数组的数据,可以考虑使用数组指针类型。
常量
常量使用关键字const定义,用于存储不会改变的数据。
常量不能被重新赋予任何值。存储在常量中的数据类型只可以是布尔型、数字型(rune、整型、浮点型和复数)和字符串型。
常量的定义格式为const identifier[type]=value,例如 const PI = 3.1415926
Go语言的常量定义可以限定常量类型,但不是必需的。如果定义常量时没有指定类型,那么它与字面常量一样,是无类型(untyped)常量。一个没有指定类型的常量在使用时,会根据其使用环境而推断出它所需要具备的类型。
Go语言预定义了这些常量字面量:true、false和iota。布尔常量只包含两个值:true和false。
iota比较特殊,可以认为它是一个可被编译器修改的常量,在每一个const关键字出现时被重置为0,然后在下一个const出现之前,每出现一次iota,其所代表的数字就会自动加1。
类型
Go中的值都被划分为不同的类型,这些类型指定了这些值的用途。整数可以用在数学运算中,但字符串不行。字符串可以大写,但是数字不能。Go中的值被分为不同的类型,这些类型指定了值的用途。不同类型之间进行数学运算和比较是不允许的。但如果需要,可以将值转换为新类型。Go变量只能存储其声明类型的值。
Go是静态类型的,这意味着它甚至在程序运行之前就知道值的类型是什么。函数期望它们的参数具有特定的类型,它们的返回值也具有类型(可能与参数类型相同,也可能不同)。如果你不小心在错误的地方使用了错误类型的值,Go会给你一个错误消息。你可以通过将任何值传递给reflect包的TypeOf函数,来查看它们的类型。让我们看看对于已经看到的一些值,它们的类型是什么:
package main
import (
"fmt"
"reflect"
)
func main() {
fmt.Println(reflect.TypeOf(1)); //int
fmt.Println(reflect.TypeOf(true)); //bool
fmt.Println(reflect.TypeOf(0.1)); //float64
fmt.Println(reflect.TypeOf("soaring")); //string
}
内建变量类型
布尔:true、false
整数:(u)int、(u)int8、(u)int16、(u)int32、(u)int64、uintptr
说明:整数类型分为两类,一类是指定长度的,另一类是非指定长度的,如果使用非指定长度的整数类型,则以操作系统支持的长度为准。其中 u 代表是无符号(unsigned),uintptr表示的是指针。
字节:byte、rune
说明:rune类似于char类型,在go语言中没有char类型,可用rune代替,表示单个文本字符。byte 8位,rune 32位,通常我们用int32代表rune
浮点型:float32、float64、complex64、complex128
说明:复数 complex64(表示32 位实数和虚数)、complex128(表示64位实数和虚数)
强制类型转换
go语言中没有隐式类型转换,类型转换是强制的。Go中的数学运算和比较运算要求包含的值具有相同的类型。如果不是的话,则在尝试运行代码时会报错。
package main import "fmt" func main() { var width int = 5 var height float64 = 4.5 // fmt.Println(width * height) //会报invalid operation: width * height (mismatched types int and float64)错误 fmt.Println(float64(width) * height) //22.5 }
在进行转换时,请注意它们可能会如何更改结果值。例如,foat64变量可以存储小数值,但是int变量不能。当你将foat64转换为int时,小数部分会被简单地删掉!这可能会抛弃用结果值执行的任何操作。