这节讲一下go语言的变量定义。go是静态语言类型,不像python、php语言,它不能在运行期间改变变量的类型(除非进行类型转换,参见 go语言入门扩展--4种类型转换)。
变量的定义常用的有3种方式:
方式1是完整的定义方式,书写比较繁琐,每次定义1个变量都要完整的写出var关键字、变量名、变量类型3个部分;
方式2和方式3可以理解为偷懒的写法。其中方式2省略了变量类型,交由编译器推断;方式3在方式2的基础上进一步偷懒(var关键字由:号代替)。
实际开发中方式3会用的比较多,但在需要明确限制变量类型的场景下,必须使用方式1
package main
import "fmt"
func main() {
a := 123 // 自动推断类型,int
b := 123.0 // 变动推断类型, float64
var c int64 = 123 // 明确指定类型,int64
fmt.Printf("a: %T\n", a)
fmt.Printf("b: %T\n", b)
fmt.Printf("c: %T\n", c)
/*
输出
a: int
b: float64
c: int64
*/
}
上面提到的3种变量定义方式,同样支持一次多个变量的声明,对应写法为:
package main
import "fmt"
func main() {
var a, b int = 1, 2 // 等同 var a, b = 1, 2
fmt.Println(a, b)
c, d := "hello", 12 // 可以不同类型
fmt.Println(c, d)
}
/*
输出:
1 2
hello 12
*/
使用多变量声明时,编译器会先计算所有的相关值,然后再从左往右依次赋值
package main
import "fmt"
func main() {
i, dataList := 0, [3]int{1, 2, 3} // i=0, dataList=[1, 2, 3]
fmt.Println(i, dataList) // 输出: 0, [1, 2, 3]
i, dataList[i] = 2, 100 // 等同i, dataList[0] = 2, 100
/*
需要注意,这个语句的效果不等同下面这2个语句:
i = 2
dataList[i] =100
编译器会先计算该语句相关项的值,经过计算后,语句等效于:
i, dataList[0] = 2, 100
可以理解为:
赋值语句x = y所表达的含义是:在x所代表的内存地址中存入值y,即=号左边是内存地址,=号右边是可确定的具体值。
回到这个语句上:
左边:
i: 变量,代表确定的内存地址
dataList[i]: 需要i来确定地址,因而带入i的值来定位具体的内存地址, i=0,因而变为dataList[0]
右边:
2个值都是确定的常量值,无需计算
*/
fmt.Println(i, dataList) // 2 [100, 2, 3]
i, dataList[i] = dataList[i], 222 // 等同 i, dataList[2] = 3, 222
/*
参照上面的理解,编译器会先计算=号左边地址相关的项、=号右边确定数值的项。
i = 2
=号左边计算可确定的内存地址: i, dataList[2]
=号右边计算可确定的值: dataList[2] , 222
因而这个语句等效于:
i, dataList[2] = dataList[2], 222
*/
fmt.Println(i, dataList) // 3 [100 2 222]
}
变量一旦声明后,便不能再重新声明,否则会报错
package main
import "fmt"
func main() {
var a int
a := 12 //no new variables on left side of :=
fmt.Println(a)
}
但如果声明语句中包含有未声明过的变量,那么是不会报错的,那些已经声明过的变量会被重新赋值(不会重新声明,仅仅重新赋值)
package main
import "fmt"
func main() {
s := "abc" // 声明并初始化了变量s
fmt.Println(&s, s) // 0xc000010240 abc
// s := "hello" 单独这个语句是不允许的,重复声明
s, y := "hello", 1 // y是新的变量,s是已经声明的变量,在这里会被重新赋值
fmt.Println(&s, s, y) // 0xc000010240 hello 1 变量s的地址没有改变,仅仅被重新赋值
}
在同一个代码作用域内,变量不能重复声明,但在不同作用域,可以声明同名变量。还是以上面的代码为例
package main
import "fmt"
func main() {
s := "abc"
fmt.Println(&s, s) // 0xc000010240 abc
s, y := "hello", 1
fmt.Println(&s, s, y) // 0xc000010240 hello 1
{ // 进入代码块
s := "world" // 不同作用域,可以声明同名变量
fmt.Println(&s, s) // 0xc000010270 world 此处s的地址值和外面s的地址值不同
} // 离开这个代码块后,作用域中的s便销毁了
fmt.Println(&s, s) // 0xc000010240 hello 留意这里s的地址值
}
编译期可以确定的值,如数字、字符串、布尔值、函数返回值等等,使用const关键字进行定义,不可修改
const x, y int = 1, 2
const msg = "hello world" // 可以不指定类型,有编译器自行推断
// 可以使用()定义一组常量,如
const (
a = "hello"
b = "world"
c = len(a) // 可以是函数返回值
d // 不给表达式,那么会采用上1个变量的表达式,即等同: d = len(a)
)
iota是一个从0开始、按行计数的自增枚举值。iota在遇到const关键字被重置为0,否则会一直按行递增。也可以同时提供多个iota,它们各自增长。中途可以打断iota(但依然会自增计数),但恢复时需要显示恢复。
package main
import "fmt"
const (
a = iota //a = 0
b //b = 1 未给表达式,采用上一个变量的表达式,即等同 b=iota
c = "hello" // 打断iota自增
d = "world"
e = iota // e = 4 显示恢复,c/d的两行会被计数,因而这里为4
)
const (
f = iota // f = 0 遇到const关键字,从0开始
g // g = 1
h = iota // h = 2
)
// 同时提供多个iota
const (
m1, n1 = iota, iota // m1=0 n1=0
m2, n2 // m2=1 n2=1
m3, n3 = "hello", iota // 打断第一个iota, m3="hello" n3=2
m4, n4 = iota, iota // 显示恢复 m4=3 n4=3
)
func main() {
fmt.Println("a=", a, "b=", b, "c=", c, "d=", d, "e=", e)//a= 0 b= 1 c= hello d= world e= 4
fmt.Println("f=", f, "g=", g, "h=", h) //f= 0 g= 1 h= 2
fmt.Println("m1=", m1, "n1=", n1) //m1= 0 n1= 0
fmt.Println("m2=", m2, "n2=", n2) // m2= 1 n2= 1
fmt.Println("m3=", m3, "n3=", n3)// m3= hello n3=2
fmt.Println("m4=", m4, "n4=", n4)// m4= 3 n4= 3
}
字符串是不可变的字节系列,通常用来存储可读的文本,其内部用指针指向UTF-8的字节数组[]byte。当字符串中的字符是ASCII码表上的字符时则占用1个字节,其他字符根据需要占用2~4个字节,比如1个中文占用3个字节。
package main
import "fmt"
func main() {
s := "hello张三"
fmt.Println(s[1], string(s[1])) // 101 e 字符e在ASCII编码表id 101
// var p *byte = &s[1] 非法 Cannot take the address of 's[1]'
// s[1] = 'o' 非法 Cannot assign to s[1]
fmt.Println(len(s), string(s[1]), string(s[5])) // 11 e å 一个中文占3个字节
rs := []rune(s)
fmt.Println(len(rs), string(rs[1]), string(rs[5])) // 7 e 张 转为rune,每个中文长度1
}
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。