Go 语言是静态类型语言,由于编译时,编译器会检查变量的类型,所以要求所有的变量都要有明确的类型
。
变量在使用前,需要先声明。声明类型,就约定了你这个变量只能赋该类型的值。
格式:var 变量名 类型 = 值
声明方式大概有四种,若声明时没有初始化,那么其默认值为该数据类型的 0 值,比如: string
类型就初始化为空字符串,int
类型就初始化为0,float
就初始化为 0.0,bool
类型就初始化为 false
,指针类型就初始化为 nil
:
1、一行声明一个变量,并初始化值
var name string = "变量"
2、一次声明多个变量
var (age intgender string)
3、声明和初始化一个变量
使用 :=
(让编译器自动根据右侧的值推测出左侧的变量数据类型),这种方法只能用于函数内部
name := "Go 变量"// 等同
var name string = "Go 变量"
4、声明和初始化多个变量
name, age := "rose", 18// 可以用来做变量交换
var a int = 100
var b int = 200
b, a = a, b
根据变量位置可将变量划分为全局变量和全局变量,Go
变量有作用域之分,每个大括号就是一个作用域,每个作用域都可以有相应的局部变量。
全局变量
全局可使用
package mainimport "fmt"// 声明全局变量
var country = "中国"func main() {fmt.Println(country)country = "China"fmt.Println(country)
}
输出:
中国
China
注意:全局变量首字母小写,只能用于当前包中,大写可用于其他包文件,即外部可使用
局部变量
仅对应作用域可使用
package mainimport "fmt"func main() {// 声明局部变量,在当前函数中使用var country = "China"fmt.Println(country)if true {// 声明局部变量,仅在 if 中使用var age = 18fmt.Println(age)fmt.Println(country)}// age 不能在 if 作用域外使用// fmt.Println(age)}
输出:
China
18
China
country
可在当前函数作用域中使用,但 age
不能在 if
作用域外使用。
变量分为两种:
指针变量声明可以使用 new
函数,也可以使用 &普通变量
:
package mainimport "fmt"func main() {// 指针变量,方法一var name string = "rose"var ptr = &name // & 后面接变量名,表示取出该变量的内存地址fmt.Println(name) // rosefmt.Println(ptr) // 0xc00005e270// 指针变量,方法二 new 函数ptr2 := new(int)fmt.Println(ptr2) // 0xc0000a6090fmt.Println(*ptr2) // * 指针变量名,表示从内存中取出值、0
}
使用表达式 new(Type)
将创建一个Type
类型的匿名变量,初始化为Type
类型的零值,然后返回变量地址,返回的指针类型为*Type
。
常量和变量都只能声明一次,声明多次就会编译报错,匿名变量除外,它有如下优点:
一般可以用来接收必须接收,但又用不到的值:
func GetData() (int, int) {return 100, 200
}
func main(){a, _ := GetData()_, b := GetData()fmt.Println(a, b)
}
常量即不可被修改的变量,支持的类型:数字型(整型、浮点型和复数)、字符串型、布尔型,如:
// 声明变量
var name = "rose"// 声明常量
var age = 18
const age1 = 18
const (v1 = 123 v2 = 456v3 = 789v4 = 101112
)
特殊变量,可以认为是一个可修改的常量,在 const
关键字出现时被重置为 0 (const
内部的第一行之前),const
每新增一行,常量声明将使 iota
计数一次,可理解为 const
语句块中的行索引。
const (v1 = iotav2 = iotav3 = iota
)
v1 = 0
,v2、v3
分别为 1、2
,可简写如下:
const (v1 = iotav2v3
)
示例一
package mainimport "fmt"func main() {const (v1 = iota + 2v2v3)fmt.Println(v1, v2, v3)const (v4 = iota + 2_v5v6)fmt.Println(v4, v5, v6)
}
输出:
2 3 4
2 4 5
示例二
package mainimport "fmt"func main() {const (i=1<
<<
:表示左移iota
初始为 0,i
左移 0 位,值不变仍为 1j
左移 1 位,变为二进制 110
,即 6k
左移 2 为,变为二进制:1100
,即 12l
左移 3 为,变为二进制:11000
,即 24注意:
<
接收输入的有三个函数,分别为:
fmt.Scan
:从标准输入扫描用户输入的数据,将以空白符分隔的数据分别存入指定的函数fmt.Scanln
:遇到换行时才停止扫描,最后一个数据后面必须有换行或者到达结束位置fmt.Scanf
:按指定格式扫描输入的数据从标准输入扫描文本,读取由空白符分隔的值保存到传递给本函数的参数中,换行符视为空白符。
本函数返回成功扫描的数据格式和遇到的任务错误,若读取的数据个数比提供的参数少,会返回一个错误报告原因。
1、接收一个参数:
package mainimport "fmt"func main() {var name stringfmt.Println("请输入用户名:")fmt.Scan(&name)fmt.Printf(name)
}
输出:
[root@localhost test]# go run test.go
请输入用户名:
rose
rose
2、接收两个参数:
package mainimport "fmt"func main() {var name stringvar age intfmt.Println("请输入用户名:")_, err := fmt.Scan(&name, &age)if err == nil {fmt.Println(name, age)} else {fmt.Println("用户输入数据错误", err)}
}
运行结果:
请输入用户名:
rose 18
rose 18
类似 Scan
,遇到换行时才停止扫描,最后一个数据后面必须有换行或者到达结束位置。
返回成功扫描的数据个数和遇到的任何错误。
package mainimport "fmt"func main() {var (name stringage intgender string)fmt.Println("请输入参数:")fmt.Scanln(&name, &age, &gender)fmt.Println(name, age, gender)
}
运行结果:
// 空格不会停止扫描
请输入参数:
rose 19 female
rose 19 female// 回车会停止扫描
请输入参数:
rose
rose 0
从标准输入扫描文本,根据 format
参数指定的格式去读取由空白符分隔的值保存到传递给本函数的参数中。
返回成功扫描的数据个数和遇到的任何错误。
package mainimport "fmt"func main() {var (name stringage int)fmt.Println("请输入参数:")_, _ = fmt.Scanf("我叫:%s 今年:%d 岁", &name, &age)fmt.Println(name, age)
}
fmt.Scanf
不能以简单的空格符作为输入数据的分隔符,它指定了具体的输入格式,只有按照格式输入数据才会被扫描并存入对应变量,否则不能正确扫描到输入的数据。
fmt.Scan
以空白符区分输入的参数,若输入的是一整行,且单次之间相互有空格,那么使用 fmt.Scan
就会报错,若想读取一整行可以使用:
package mainimport ("bufio""fmt""os"
)func main() {reader := bufio.NewReader(os.Stdin)// line 从 stdin 中读取一行的数据,字节集合,转换为字符串line, _, _ := reader.ReadLine()data := string(line)fmt.Println(data)
}
运行结果:
// 输入的数据
格式化输入输出的用法请参考 aaaa fff gghh arr// 打印的数据
格式化输入输出的用法请参考 aaaa fff gghh arr
reader
默认一次能读取 4096
个字节,一次性读完:isPrefix=false
,先读一部分:isPrefix=true
,再去读取:isPrefix=false
。