Go基础|第3章:基本类型、变量与常量
Synopsis: Go 语言将数据类型分为四类:基本类型、复合类型、引用类型和接口类型,本文仅简单介绍下布尔型、字符串、整型、浮点型、复数等基本类型,各类型的详细说明可以参考《The Go Programming Language》,然后学习如何声明变量和常量
1. 基本类型
Go 的基本类型有三类:
- 布尔型
bool
: 只有true
和false
两种值,支持以下逻辑运算符- 与
&&
- 或
||
- 非
!
- 与
- 字符串
string
: 是一个不可改变的字节序列,文本字符串通常被解释为采用 UTF8 编码的 Unicode code point(rune
)序列。注意: 内置的len()
函数返回一个字符串中的字节数目(不是 rune 字符数目) - 数值型
- 整数
int
/int8
/int16
/int32
/int64
/uint
/uint8
/uint16
/uint32
/uint64
/uintptr
/byte
/rune
- 浮点数
float32
/float64
- 复数
complex64
/complex128
- 整数
其中 byte
是 uint8
的别名。rune
是 int32
的别名,表示一个 Unicode code point(比如字符 𪸿
的 Unicode 码点为 U+2AE3F
,十六进制转换为十进制后的整数为 175679
):
// byte is an alias for uint8 and is equivalent to uint8 in all ways. It is // used, by convention, to distinguish byte values from 8-bit unsigned // integer values. type byte = uint8 // Go 1.9 开始用户也可以声明自定义的类型别名(type alias) // rune is an alias for int32 and is equivalent to int32 in all ways. It is // used, by convention, to distinguish character values from integer values. type rune = int32
注意: 字符串必须用双引号,比如
"hello"
。单引号表示一个 rune 字符,比如'𪸿'
2. 变量
使用 var
关键字来声明一个或多个变量,注意类型在变量名之后
package main import "fmt" // 包级别声明的变量会在 main 入口函数执行前完成初始化 var a int = 10 func main() { fmt.Printf("%T %v\n", a, a) // 局部变量将在声明语句被执行到的时候完成初始化 var b int = 20 fmt.Printf("%T %v\n", b, b) // 可以在一个声明语句中同时声明一组变量:变量类型相同时,保留最后的类型即可 var c, d bool = true, false fmt.Printf("%T %v\n", c, c) fmt.Printf("%T %v\n", d, d) // 可以在一个声明语句中同时声明一组变量:变量类型不同时,不能分别写类型,由 Go 自动进行类型推导 var e, f = "hello", 3.14 fmt.Printf("%T %v\n", e, e) fmt.Printf("%T %v\n", f, f) } /* Output: int 10 int 20 bool true bool false string hello float32 3.14 */
使用小括号 分组
形式声明多个变量:
一组变量也可以通过调用一个函数,由函数返回的多个返回值初始化:
2.1 零值
声明变量时,这个变量对应的值总是会被初始化。要么用指定的值初始化,要么用变量类型的默认值 零值(zero value)
做初始化
- 布尔型:
false
- 字符串:
""
(空字符串) - 数值型:
0
package main import "fmt" func main() { var b bool var s string var i int var f float64 fmt.Printf("%v %q %v %v\n", b, s, i, f) } /* Output: false "" 0 0 */
其它零值:
- 引用类型(function、slice、map、channel、pointer 和 interface)对应的零值是
nil
- array 或 struct 等聚合类型对应的零值是每个元素或字段所对应的类型的零值
零值初始化机制可以确保每个声明的变量总是有一个良好定义的值,因此在 Go 语言中不存在未初始化的变量。这个特性可以简化很多代码,而且可以在没有增加额外工作的前提下确保边界条件下的合理行为
2.2 类型推导
在声明一个变量而不指定其类型时,变量的类型由右值推导得出
package main import "fmt" func main() { var b, s, i, f = false, "hello", 10, 3.14 fmt.Printf("%T %v\n", b, b) fmt.Printf("%T %v\n", s, s) fmt.Printf("%T %v\n", i, i) fmt.Printf("%T %v\n", f, f) } /* Output: bool false string hello int 10 float64 3.14 */
当右值声明了类型时,新变量的类型与其相同:
2.3 短变量声明
在 函数(比如 func main() {...}
)中,如果右值的类型明确,可以用 :=
代替 var
声明变量。短变量声明 :=
在一次操作中完成两件事情:声明一个变量、并初始化
函数外的每个语句都必须以关键字开始(比如
import
、var
等),因此:=
只能在函数内使用
package main import "fmt" // var 声明变量可以出现在函数外 var b bool = false // b := false // 报错: syntax error: non-declaration statement outside function body func main() { // var 声明变量也可以出现在函数内 var s = "hello" // 短变量声明 := 只能出现在函数内 i, f := 10, 3.14 fmt.Printf("%T %v\n", b, b) fmt.Printf("%T %v\n", s, s) fmt.Printf("%T %v\n", i, i) fmt.Printf("%T %v\n", f, f) } /* Output: bool false string hello int 10 float64 3.14 */
注意:
:=
是一个变量声明语句,而=
是一个变量赋值操作
和普通 var 形式的变量声明语句一样,短变量声明语句也可以用函数的返回值来声明和初始化变量:
// 注意: f 和 err 至少有一个变量之前未被声明过,或者会报错 compile error: no new variables,此时只能使用 = 赋值操作 f, err := os.Open(name) defer f.Close() if err != nil { return err }
要特别注意短变量声明语句的作用域范围:
package main import ( "fmt" "log" "os" ) var cwd string func init() { cwd, err := os.Getwd() // 不同代码块中的重名变量 cwd if err != nil { log.Fatalf("os.Getwd failed: %v", err) } // 如果注释掉下面的语句编译不通过,因为内部重声明的 cwd 变量未使用 // compile error: cwd declared and not used fmt.Printf("Working directory = %s \n", cwd) } func main() { fmt.Printf("%T %q\n", cwd, cwd) } /* Output: Working directory = D:\MyCode\go-in-action string "" */
虽然 cwd 在外部已经声明过,但是 :=
语句声明的 cwd 和 err 是新的局部变量,与外部的 cwd 属于不同的代码块,所以可以重名(不同代码块中的重名变量)。而 变量重声明
是在同一个代码块内,且只用于 := 语句中,比如:
func foo() { var err error n, err := io.WriteString(os.Stdout, "Hello, everyone!\n") // err 为变量重声明 ... }
因为内部声明的 cwd 将 屏蔽
外部的声明,所以上面的代码并不会正确更新包级声明的 cwd 变量值。为了避免出现类似潜在的问题,最直接的方法是通过单独声明 err 变量,来避免使用 :=
简短声明方式:
package main import ( "fmt" "log" "os" ) var cwd string func init() { var err error cwd, err = os.Getwd() // 不使用 := if err != nil { log.Fatalf("os.Getwd failed: %v", err) } // 即使注释掉下面的语句也不会报错了 fmt.Printf("Working directory = %s \n", cwd) } func main() { fmt.Printf("%T %q\n", cwd, cwd) } /* Output: Working directory = D:\MyCode\go-in-action string "D:\\MyCode\\go-in-action" */
2.4 类型转换
表达式 T(v)
的意思是,将值 v
的类型转换为 T
类型,如果两个类型之间无法转换时,将报错:cannot convert v (type a) to type b
package main import "fmt" func main() { // 等价于 var i int = 42 i := 42 fmt.Printf("%T %v\n", i, i) // 等价于 var f float64 = float64(i) f := float64(i) fmt.Printf("%T %v\n", f, f) } /* Output: int 42 float64 42 */
3. 常量
常量的声明与变量类似,只不过是使用 const
关键字,常量可以被赋值为布尔值、字符/字符串、数值
使用小括号 分组
形式声明多个常量:
注意: 不能使用
:=
语法声明常量
package main import "fmt" // const 声明常量可以出现在函数外 const b bool = false func main() { // const 声明常量也可以出现在函数内 const s = "hello" // const i // 报错: missing value in const declaration,常量必须被明确赋值,没有零值的概念 // const i, f := 10, 3.14 // 报错: syntax error: unexpected :=, expecting = // 类型推导 const i, f = 10, 3.14 fmt.Printf("%T %v\n", b, b) fmt.Printf("%T %v\n", s, s) fmt.Printf("%T %v\n", i, i) fmt.Printf("%T %v\n", f, f) // i = 20 // 报错: cannot assign to i,常量不可变 } /* Output: bool false string hello int 10 float64 3.14 */
0 条评论
评论者的用户名
评论时间暂时还没有评论.