搭建完Go的开发环境之后,我们就能开始愉快的编程了。
接下来就学习Go语言的类型有那些,他如何定义变量,常量。
1. 变量与常量
1.1 变量声明
Go 是静态类型语⾔,不能在运⾏期改变变量类型。
使⽤关键字 var 定义变量,每个变量会被初始化成其类型的默认值,例如: 整型和浮点型变量的默认值为0。 字符串变量的默认值为空字符串。 布尔型变量默认为false
。 切片、函数、指针变量的默认为nil
。
// 标准声明
var number int
var str string
var isOk bool
fmt.Println(number)
fmt.Println(str)
fmt.Println(isOk)
fmt.Println("====================")
// 批量声明
var (
number1 int
str1 string
isOk1 bool
)
fmt.Println(number1)
fmt.Println(str1)
fmt.Println(isOk1)
复制代码
结果如下:
1.2 变量初始化
变量的初始化有很多种方式,标准的是这样: var 变量名 类型 = 表达式
var str2 string = "string"
var number2 int = 1
// 或者这样,一次性初始化多个变量
var str3, number3 = "string", 2
复制代码
类型推导
将变量的类型省略,编译器会根据等号右边的值来推导变量的类型完成初始化。
var str4 = "string"
var number4 = 4
// 打印结果
// 4
// string
复制代码
短变量声明
在函数内部,可以使用更简略的 := 方式声明并初始化变量。
package main
import (
"fmt"
)
// 全局变量m
var m = 100
func main() {
n := 10
m := 200 // 此处声明局部变量m
fmt.Println(m, n)
}
复制代码
匿名变量
在使用多重赋值时,如果想要忽略某个值,可以使用匿名变量(anonymous variable)。 匿名变量用一个下划线_表示,例如:
package main
import (
"fmt"
)
func main() {
number5, _ := test()
_, str5 := test()
fmt.Println(number5)
fmt.Println(str5)
}
func test() (int, string) {
return 20, "string"
}
复制代码
匿名变量不占用命名空间,不会分配内存,所以匿名变量之间不存在重复声明。
1.3 常量
常量定义
相对于变量,常量是恒定不变的值,多用于定义程序运行期间不会改变的那些值。 常量的声明和变量声明非常类似,只是把var
换成了const
,常量在定义的时候必须赋值
const PI = 3.14
const OTHER = "other"
const (
PIL = 3.14
OTHERL = "other"
)
复制代码
同时声明多个常量,如果省略了值则和上一行的值相同
const (
A = "A"
B
C
D = "D"
E
)
println(A, B, C, D, E) // A A A D D
复制代码
1.4 iota
iota
是go
语言的常量计数器,只能在常量的表达式中使用。 iota
在const
关键字出现时将被重置为0
。const
中每新增一行常量声明将使iota
计数一次(iota
可理解为const
语句块中的行索引)。 使用iota
能简化定义,在定义枚举时很有用。
const (
F = iota
G
H
I
J
)
println(F, G, H, I, J) //0 1 2 3 4
复制代码
使用_跳过某些值
const (
n1 = iota //0
n2 //1
_
n4 //3
)
复制代码
iota
声明中间插队
const (
n1 = iota //0
n2 = 100 //100
n3 = iota //2
n4 //3
)
const n5 = iota //0
复制代码
定义数量级 (这里的<<
表示左移操作,1<<10
表示将1
的二进制表示向左移10
位,也就是由1
变成了10000000000
,也就是十进制的1024
。同理2<<2
表示将2
的二进制表示向左移2
位,也就是由10
变成了1000
,也就是十进制的8
。)
const (
_ = iota
KB = 1 << (10 * iota)
MB = 1 << (10 * iota)
GB = 1 << (10 * iota)
TB = 1 << (10 * iota)
PB = 1 << (10 * iota)
)
复制代码
多个iota
定义在一行
const (
a, b = iota + 1, iota + 2 //1,2
c, d //2,3
e, f //3,4
)
复制代码
2. 基本类型介绍
Golang 更明确的数字类型命名,支持 Unicode,支持常用数据结构。
类型 | 长度(字节) | 默认值 | 说明 |
---|---|---|---|
bool | 1 | false | |
byte | 1 | 0 | uint8 |
rune | 4 | 0 | Unicode Code Point, int32 |
int, uint | 4或8 | 0 | 32 或 64 位 |
int8, uint8 | 1 | 0 | -128 ~ 127, 0 ~ 255,byte是uint8 的别名 |
int16, uint16 | 2 | 0 | -32768 ~ 32767, 0 ~ 65535 |
int32, uint32 | 4 | 0 | -21亿~ 21亿, 0 ~ 42亿,rune是int32 的别名 |
int64, uint64 | 8 | 0 | |
float32 | 4 | 0.0 | |
float64 | 8 | 0.0 | |
complex64 | 8 | ||
complex128 | 16 | ||
uintptr | 4或8 | 以存储指针的 uint32 或 uint64 整数 | |
array | 值类型 | ||
struct | 值类型 | ||
string | "" | UTF-8 字符串 | |
slice | nil | 引用类型 | |
map | nil | 引用类型 | |
channel | nil | 引用类型 | |
interface | nil | 接口 | |
function | nil | 函数 |
支持八进制、 六进制,以及科学记数法。标准库 math 定义了各数字类型取值范围。
a, b, c, d := 071, 0x1F, 1e9, math.MinInt16
空指针值 nil,而非C/C++ NULL。
2.1 整型
整型分为以下两个大类: 按长度分为:int8
、int16
、int32
、int64
对应的无符号整型:uint8
、uint16
、uint32
、uint64
其中,uint8
就是我们熟知的byte
型,int16
对应C语言中的short
型,int64
对应C语言中的long
型。
挺好奇go语言的int位数是多少:
import (
"fmt"
"runtime"
"strconv"
)
func main() {
fmt.Println("cpu型号:", runtime.GOARCH)
fmt.Println("int位数:", strconv.IntSize)
}
复制代码
然后运行结果如下:
64位操作系统int
位数是64。
2.2 浮点型
Go语言支持两种浮点型数:float32
和float64
。这两种浮点型数据格式遵循IEEE 754
标准: float32
的浮点数的最大范围约为3.4e38
,可以使用常量定义:math.MaxFloat32
。 float64
的浮点数的最大范围约为 1.8e308
,可以使用一个常量定义:math.MaxFloat64
。
2.3 复数
complex64
和complex128
复数有实部和虚部,complex64
的实部和虚部为32位,complex128
的实部和虚部为64位。
2.4 布尔值
Go语言中以bool
类型进行声明布尔型数据,布尔型数据只有true(真)
和false(假)
两个值。注意:
- 布尔类型变量的默认值为false。
- Go 语言中不允许将整型强制转换为布尔型.
- 布尔型无法参与数值运算,也无法与其他类型进行转换。
2.5 字符串
Go语言中的字符串以原生数据类型出现,使用字符串就像使用其他原生数据类型(int、bool、float32、float64 等)
一样。 Go 语言里的字符串的内部实现使用UTF-8编码。 字符串的值为双引号(")中的内容,可以在Go语言的源码中直接添加非ASCII
码字符,例如:
s1 := "hello"
s2 := "你好"
复制代码
2.6 多行字符串
Go语言中要定义一个多行字符串时,就必须使用反引号
字符:
s1 := `第一行
第二行
第三行
`
fmt.Println(s1)
复制代码
反引号间换行将被作为字符串中的换行,但是所有的转义字符均无效,文本将会原样输出。
2.7 字符串转义符
Go 语言的字符串常见转义符包含回车、换行、单双引号、制表符等,如下表所示。
转义 | 含义 |
---|---|
\r | 回车符(返回行首) |
\n | 换行符(直接跳到下一行的同列位置) |
\t | 制表符 |
' | 单引号 |
" | 双引号 |
反斜杠 |
举个例子,我们要打印一个Windows平台下的一个文件路径:
package main
import (
"fmt"
)
func main() {
fmt.Println("str := "c:\pprof\main.exe"")
}
复制代码
2.8 字符串的常用操作
方法 | 介绍 |
---|---|
len(str) | 求长度 |
+或fmt.Sprintf | 拼接字符串 |
strings.Split | 分割 |
strings.Contains | 判断是否包含 |
strings.HasPrefix,strings.HasSuffix | 前缀/后缀判断 |
strings.Index(),strings.LastIndex() | 子串出现的位置 |
strings.Join(a[]string, sep string) | join操作 |
2.9 byte和rune类型
组成每个字符串的元素叫做“字符”,可以通过遍历或者单个获取字符串元素获得字符。 字符用单引号(')包裹起来,如:
var a := '中'
var b := 'x'
复制代码
Go 语言的字符有以下两种:
- uint8类型,或者叫 byte 型,代表了ASCII码的一个字符。
- rune类型,代表一个 UTF-8字符。
当需要处理中文、日文或者其他复合字符时,则需要用到rune
类型。rune
类型实际是一个int32
。 Go 使用了特殊的 rune
类型来处理 Unicode
,让基于 Unicode
的文本处理更为方便,也可以使用 byte
型进行默认字符串处理,性能和扩展性都有照顾
// 遍历字符串
func printStr() {
str := "abcdefg 哈哈哈"
for i := 0; i < len(str); i++ { // byte 1字节
fmt.Printf("%v(%c)", str[i], str[i])
}
fmt.Println()
fmt.Println("==========")
for _, r := range str { // rune 4字节 单个字符
fmt.Printf("%v(%c)", r, r)
}
}
复制代码
输出:
97(a)98(b)99(c)100(d)101(e)102(f)103(g)32( )229(å)147()136()229(å)147()136()229(å)147()136()
==========
97(a)98(b)99(c)100(d)101(e)102(f)103(g)32( )21704(哈)21704(哈)21704(哈)
复制代码
因为UTF8编码下一个中文汉字由3~4
个字节组成,所以我们不能简单的按照字节去遍历一个包含中文的字符串,否则就会出现上面输出中第一行的结果。
字符串底层是一个byte数组,所以可以和[]byte类型相互转换。字符串是不能修改的 字符串是由byte字节组成,所以字符串的长度是byte字节的长度。 rune类型用来表示utf8字符,一个rune字符由4个byte组成。
2.10 修改字符串
要修改字符串,需要先将其转换成[]rune或[]byte
,完成后再转换为string
。无论哪种转换,都会重新分配内存,并复制字节数组。
func changeStr() {
str1 := "hello 你好"
byte1 := []byte(str1)
fmt.Println(string(byte1)) // 强转
byte1[0] = 'H'
byte1[1] = 'H'
fmt.Println(string(byte1)) // 强转
str2 := "你好"
rune2 := []rune(str2)
fmt.Println(string(rune2)) // 强转
rune2[0] = '我'
fmt.Println(string(rune2)) // 强转
}
复制代码
运行结果
hello 你好
HHllo 你好
你好
我好
复制代码
2.11 类型转换
Go语言中只有强制类型转换,没有隐式类型转换。该语法只能在两个类型之间支持相互转换的时候使用。
强制类型转换的基本语法如下:
T(表达式)
其中,T表示要转换的类型。表达式包括变量、复杂算子和函数返回值等.
比如计算直角三角形的斜边长时使用math包的Sqrt()函数,该函数接收的是float64类型的参数,而变量a和b都是int类型的,这个时候就需要将a和b强制类型转换为float64类型。
func sqrtDemo() {
var a, b = 3, 4
var c int
// math.Sqrt()接收的参数是float64类型,需要强制转换
c = int(math.Sqrt(float64(a*a + b*b)))
fmt.Println(c)
}
复制代码
支持的类型转换
注释了的都是不能转到
func changeVarType() {
// var v = "dd"
// fmt.Println(int(v))
// fmt.Println(byte(v))
// fmt.Println(rune(v))
// fmt.Println(float32(v))
var v = 'D'
fmt.Println(string(v))
fmt.Println(byte(v))
fmt.Println(float32(v))
// fmt.Println(bool(v))
// fmt.Println(complex64(v))
}
复制代码
类型断言
变量.(type)
,有两个返回值,第一个是对应类型的值,第二个是bool类型的,类型判断是否正确。
func printType() {
var a interface{} = "value" // interface{} 代表变量可以是任何类型,不这么些,执行时会报错
val, isInt := a.(int)
fmt.Println(val, isInt)
val2, isString := a.(string)
fmt.Println(val2, isString)
}
// 结果
0 false
value true
复制代码
switch断言
func caseType() {
var v interface{} = "string"
switch v.(type) {
case int:
fmt.Print("int")
case string:
fmt.Print("string")
}
}
复制代码
近期评论