Go语言文件的基本结构
package main //声明属于什么包
//导入语句
import "fmt"
//函数外面只能声明标识符(变量、常量、函数、类型)
//程序的入口函数
func main() {
fmt.Println("Hello world!")
}
创建实验目录
PS C:\Users\kaikai\Desktop\golang\001> go mod init 001 #001就是项目,一个项目只允许有一个入口,以后会经常使用
go: creating new go.mod: module 001
go: to add module requirements and sums:
go mod tidy
PS C:\Users\kaikai\Desktop\golang\001> go mod tidy
变量和常量
声明变量
格式:var name 类型
//声明变量 注释使用//注释内容 或者是/* 注释内容 */
var name string
var age int
var isOk bool
//批量声明
var (
name string
age int
isOk bool
)
Go语言中的变量必须先声明再使用,但是全局变量没有这个限制,在函数内部定义的变量不使用会造成编译不通过
package main
//1.这里不会造成编译不通过
var data int
func main() {
//2.这里定义不使用编译不通过
var data int
}
声明变量推荐使用骆驼命名法方法
变量赋值
声明变量同时赋值(不推荐)
var s1 string = "kaikai"
fmt.Print(s1)
----输出结果----
kaikai
类型推导
根据值判断这个变量是什么类型
var s2 = "20"
fmt.Print(s2)
----输出结果----
20
短变量声明
只能在函数内部使用,可以使用更简略的:=方式声明并初始化变量
s3 := "凯凯王"
fmt.Println(s3)
----输出结果----
凯凯王
匿名变量
在使用多重赋值时,如果想要忽略某一个值,可以使用匿名变量(anonymous variable)。匿名变量用一个下划线_
存在的意义,处理声明不使用的变量,表示忽略某一个值
package main
import "fmt"
func foo() (int, string) {
return 10, "kaikai"
}
func main() {
x, _ := foo()
_, y := foo()
fmt.Println("x=", x)
fmt.Println("y=", y)
}
----输出结果----
x= 10
y= kaikai
在同一个作用域不能重复声明两个名字一样的变量
常量
相对于变量,常量是恒定不变的量
定义了常量是不能修改的,在运行期间不能修改
命名常量
const pi = 3.141592654
const kaikai = "你说呢"
批量命名常量
const (
statusOk = 200
notFound = 404
)
//批量声明常量,如果一行声明没有赋值,默认就和上一行是一致
package main
import "fmt"
const (
n1 = 100
n2
n3
)
func main() {
fmt.Println(n1, n2, n3)
}
----输出结果----
100 100 100
iota
iota是go语言的常量计算器,只能在常量的表达式中使用
iota在const关键字出现时将重置为0,const中每新增一行常量声明将使iota计数一次(iota可理解为const语句块中的行索引)
const (
a1 = iota //0
a2 //1
a3 //2
)
几个常见的iota示例:
使用_跳过某些值
const (
c1 = iota //0
c2 = iota //1
_ = iota //2
c3 = iota //3
)
iota声明中间插队
const (
d1 = iota //0
d2 = 100 //100
d3 = iota //2
d4 //3
)
多个变量在同一行
const (
e1, e2 = iota + 1, iota + 2 //e1=1,e2=2
e3, e4 = iota + 1, iota + 2 //e3=2,e4=3s
)
定义数量级
package main
import "fmt"
const (
_ = iota
KB = 1 << (10 * iota)
MB = 1 << (10 * iota)
GB = 1 << (10 * iota)
TB = 1 << (10 * iota)
PB = 1 << (10 * iota)
)
func main() {
fmt.Println(KB, MB, GB, TB, PB)
}
----输出结果----
1024 1048576 1073741824 1099511627776 1125899906842624
fmt函数的使用
- fmt.Print:在终端中输出要打印的内容
- fmt.Println:%s占位符 使用name 这个变量的值去替换占位符
- fmt.Printf:打印完指定的内容之后会在后面加一个换行符
在Go语言中间无格式的限制,也可以使用go fmt 程序代码 来格式代码
- fmt.Println() 快速打印一个空行
fmt 包的格式化功能,你可以参考这里去看上面的代码
%b 表示为二进制
%c 该值对应的unicode码值
%d 表示为十进制
%o 表示为八进制
%q 该值对应的单引号括起来的go语法字符字面值,必要时会采用安全的转义表示
%x 表示为十六进制,使用a-f
%X 表示为十六进制,使用A-F
%v 查看值
%#v 加上描述符
%s 字符串类型
%U 表示为Unicode格式:U+1234,等价于"U+%04X"
%E 用科学计数法表示
%f 用浮点数表示
%T 查看类型
注释
行注释
基本语法: // 注释内容
在每一行的前面加上两个斜杆就可以注释这一行了。
ctrl + / 就会把你选中的多行代码全都注释。
块注释
基本语法:/*
注释内容
*/
这就相当于python里的“”“ 多行注释内容 ”“”
注:块注释里面不能有块注释,也就是说不能有嵌套
Go语言基本数据类型
整型
- 有符号整型:int8、int16、int32、int64、int;
- 无符号整型:uint8、uint16、uint32、uint64、uint。
类型 | 字节数 | 取值范围 | 说明 |
---|---|---|---|
int8 | 1 | -128~127 | 有符号8位整型 |
uint8 | 1 | 0~255 | 无符号8位整型 |
int16 | 2 | -32768~32767 | 有符号16位整型 |
uint16 | 2 | 0~65535 | 无符号16位整型 |
int32 | 4 | -2147483648~2147483647 | 有符号32位整型 |
uint32 | 4 | 0~4294967295 | 无符号32位整型 |
int64 | 8 | -9223372036854775808~9223372036854775807 | 有符号64位整型 |
uint64 | 8 | 0~18446744073709551615 | 无符号64位整型 |
声明方式如下所示:
var a int8 // 声明有符号 8 位整型
var b uint8 // 声明无符号 8 位整型
特殊整型
类型 | 字节数 | 取值范围 | 说明 |
---|---|---|---|
int | 4或8 | 取决于平台 | 有符号32或64位整型 |
uint | 4或8 | 取决于平台 | 无符号32或64位整型 |
uintptr | 4或8 | 取决于平台 | 用于存放一个指针 |
不同进制数
不同进制的表示方法
出于习惯,在初始化数据类型为整型的变量时,我们会使用10进制的表示法,因为它最直观,比如这样,表示整数10.
var num int = 10
不过,你要清楚,你一样可以使用其他进制来表示一个整数,这里以比较常用的2进制、8进制和16进制举例。
2进制:以0b
或0B
为前缀
var num01 int = 0b1100
8进制:以0o
或者 0O
为前缀
var num02 int = 0o14
16进制:以0x
为前缀
var num03 int = 0xC
下面用一段代码分别使用二进制、8进制、16进制来表示 10 进制的数值:12
package main
import (
"fmt"
)
func main() {
//十进制
var i1 = 111
fmt.Printf("%d\n", i1) // 十进制
fmt.Printf("%b\n", i1) // 十进制转换为二进制
fmt.Printf("%o\n", i1) // 十进制转换为八进制
fmt.Printf("%x\n", i1) // 十进制转换为十六进制
//八进制
i2 := 077
fmt.Printf("%d\n", i2)
//十六进制
i3 := 0x12345
fmt.Printf("%d\n", i3)
//使用%T查看变量的类型
fmt.Printf("%T\n", i3)
var num01 int = 0b1100
var num02 int = 0o14
var num03 int = 0xC
fmt.Printf("2进制数 %b 表示的是: %d \n", num01, num01)
fmt.Printf("8进制数 %o 表示的是: %d \n", num02, num02)
fmt.Printf("16进制数 %X 表示的是: %d \n", num03, num03)
}
----输出结果----
111
1101111
157
6f
63
74565
int
2进制数 1100 表示的是: 12
8进制数 14 表示的是: 12
16进制数 C 表示的是: 12
浮点型
浮点数类型的值一般由整数部分、小数点“.
”和小数部分组成。
其中,整数部分和小数部分均由10进制表示法表示。不过还有另一种表示方法。那就是在其中加入指数部分。指数部分由“E”或“e”以及一个带正负号的10进制数组成。比如,3.7E-2
表示浮点数0.037
。又比如,3.7E+1
表示浮点数37
。
有时候,浮点数类型值的表示也可以被简化。比如,37.0
可以被简化为37
。又比如,0.037
可以被简化为.037
。
有一点需要注意,在Go语言里,浮点数的相关部分只能由10进制表示法表示,而不能由8进制表示法或16进制表示法表示。比如,03.7
表示的一定是浮点数3.7
。
float32 和 float64
Go语言中提供了两种精度的浮点数 float32 和 float64。
float32,也即我们常说的单精度,存储占用4个字节,也即4*8=32位,其中1位用来符号,8位用来指数,剩下的23位表示尾数
float64,也即我们熟悉的双精度,存储占用8个字节,也即8*8=64位,其中1位用来符号,11位用来指数,剩下的52位表示尾数 (go中间小数默认就是float64)
- 常量 math.MaxFloat32 表示 float32 能取到的最大数值,大约是 3.4e38;
- 常量 math.MaxFloat64 表示 float64 能取到的最大数值,大约是 1.8e308;
- float32 和 float64 能表示的最小值分别为 1.4e-45 和 4.9e-324。
布尔值
-
使用bool声明,只有true和false
-
默认是false
-
不允许将整型强制转换为布尔值
-
布尔值无法参与数值运算,也无法于其他类型进行转换
字符串
- 内部使用的是UTF-8编码
- 包裹字符串的符号为(“”)双引号,单引号包裹的是字符
package main
import (
"fmt"
)
func main() {
//字符串
s := "hello kaikai"
//单独的字母、汉字、符合表示一个字符
c1 := 'h'
c2 := '1'
c3 := "凯"
//字节:1字节=8Bit(8个二进制位)
//1个字符'A'=1个字节
//1个utf8编码的汉字一般占3个字节
fmt.Printf(s, c1, c2, c3)
}
----输出结果----
hello kaikai%!(EXTRA int32=104, int32=49, string=凯)
字符串转义符
\r:回车符(返回行首)
\t: 表示一个制表符,通常使用它可以排版。
\n :换行符(直接跳到下一行的同列位置)
\' :单引号
\" :双引号
\\ : 反斜杠
字符串赋值
单行赋值
s1 := "我是一个好人"
多行赋值
s2 := `
人生路
天天学
学不完
够用就行
`
字符串的常用操作
方法 | 介绍 |
---|---|
len(str) | 求长度 |
+或fmt.Sprintf | 拼接字符串 |
strings.Split | 分割 |
strings.contains | 判断是否包含 |
strings.HasPrefix,strings.HasSuffix | 前缀/后缀判断 |
strings.Index(),strings.LastIndex() | 子串出现的位置 |
strings.Join(a[]string, sep string) | join操作 |
byte和rune类型
Go 语言的字符有以下两种:
uint8
类型,或者叫 byte 型,代表了ASCII码
的一个字符。rune
类型,代表一个UTF-8字符
。
当需要处理中文、日文或者其他复合字符时,则需要用到rune
类型。rune
类型实际是一个int32
因为UTF8编码下一个中文汉字由3~4个字节组成,所以我们不能简单的按照字节去遍历一个包含中文的字符串,否则就会出现上面输出中第一行的结果。
字符串底层是一个byte数组,所以可以和[]byte
类型相互转换。字符串是不能修改的 字符串是由byte字节组成,所以字符串的长度是byte字节的长度。 rune类型用来表示utf8字符,一个rune字符由一个或多个byte组成。
修改字符串
要修改字符串,需要先将其转换成[]rune
或[]byte
,完成后再转换为string
。无论哪种转换,都会重新分配内存,并复制字节数组。
package main
import (
"fmt"
)
func main() {
s1 := "big"
// 强制类型转换
byteS1 := []byte(s1)
byteS1[0] = 'p'
fmt.Println(string(byteS1))
s2 := "白萝卜"
runeS2 := []rune(s2) //把字符串强制转换成一个rune切片
runeS2[0] = '红'
fmt.Println(string(runeS2))
}
----输出结果----
pig
红萝卜
类型转换
go 存在常见的类型转换分别为:断言、强制。
package main
import "fmt"
func main() {
var a float32 = 5.6
var b int = 10
fmt.Println (a * b)
}
这样的代码会报错,因为类型不匹配
这时候需要强制类型转换
转换格式 表达式 T(v)
package main
import "fmt"
func main() {
var a float32 = 5.6
var b int = 10
fmt.Println (a * float32(b))
}
这样就不会报错了
func main() {
var a int32 = 1999999 // 小转大一样要显示转换
var b float64 = float64(a) // a转b a本身数据类型并不会改变,只是把a的值的值转成了float64
var c int8 = int8(a) // 大转小不会报错,但是数据溢出会丢失数据
fmt.Println(c)
fmt.Printf("%T,%T,%T", a, b, c)
}
----运行结果----
127
int32,float64,int8
普通变量类型int,float,string 都可以使用 type (a)
这种形式来进行强制类型转换,比如
var a int32 = 10
var b int64 = int64(a)
var c float32 = 12.3
var d float64 =float64(c)
指针也是有类型的
基本类型转string
func main() {
var (
num1 int = 9
num2 float64 = 9.99
b bool = false
c byte = 'a'
str string
)
str = fmt.Sprintf("%d", num1)
fmt.Printf("str的类型: %T\t 值:%v\n ", str, str)
str = fmt.Sprintf("%f", num2)
fmt.Printf("str的类型: %T\t 值:%v\n ", str, str)
str = fmt.Sprintf("%t", b)
fmt.Printf("str的类型: %T\t 值:%v\n ", str, str)
str = fmt.Sprintf("%c", c)
fmt.Printf("str的类型: %T\t 值:%v\n ", str, str)
}
----运行结果----
str的类型: string 值:9
str的类型: string 值:9.990000
str的类型: string 值:false
str的类型: string 值:a
数字转字符串类型
strconv.Itoa 可以将数字转换成字符串类型的数字
func main() {
var (
num int = 24
num2 float64 = 1.111
str string
)
// FormatInt参数1:要转的变量 参数2:进制
str = strconv.FormatInt(int64(num), 10)
fmt.Printf("str的类型: %T\t 值:%v\n ", str, str)
// strconv.FormatInt也可以用来转换进制,比如将10进制转换为2进制,其它进制,换掉后面的数字就可以了
str = strconv.FormatInt(123, 2)
fmt.Printf("str的类型: %T\t 值:%v\n ", str, str)
// 'f':格式 10:保留10位 64:float64
str = strconv.FormatFloat(num2, 'f', 10, 64)
fmt.Printf("str的类型: %T\t 值:%v\n ", str, str)
str = strconv.FormatBool(false)
fmt.Printf("str的类型: %T\t 值:%v\n ", str, str)
str = strconv.Itoa(num) //
fmt.Printf("str的类型: %T\t 值:%v\n ", str, str)
}
----运行结果----
str的类型: string 值:24
str的类型: string 值:1111011
str的类型: string 值:1.1110000000
str的类型: string 值:false
str的类型: string 值:24
指针的强制类型
指针的强制类型转换需要用到unsafe包中的函数实现
package main
import "unsafe"
import "fmt"
func main() {
var a int =10
var b *int =&a
var c *int64 = (*int64)(unsafe.Pointer(b))
fmt.Println(*c)
}
string转基本类型
func main() {
var (
str string = "123"
i int64 // 这里只能用int64
f float64
b bool
)
// str:字符串 base:进制 bitSize:int64
i, _ = strconv.ParseInt(str, 10, 64)
fmt.Printf("i的类型: %T\t 值:%v\n ", i, i)
f, _ = strconv.ParseFloat(str, 64)
fmt.Printf("f的类型: %T\t 值:%v\n ", f, f)
b, _ = strconv.ParseBool(str)
fmt.Printf("b的类型: %T\t 值:%v\n ", b, b)
s, _ := strconv.Atoi("str")
fmt.Printf("s的类型: %T\t 值:%v\n ", s, s)
}
----运行结果----
i的类型: int64 值:123
f的类型: float64 值:123
b的类型: bool 值:false
s的类型: int 值:0
字符串转字节切片
func main() {
// 字符串转切片
var b = []byte("itzhuzhu")
fmt.Printf("b=%v\n", b)
// 切片转字符串
var str = string([]byte{97, 98, 99})
fmt.Printf("str=%v\n", str)
}
----运行结果----
b=[105 116 122 104 117 122 104 117]
str=abc
类型断言
package main
import "fmt"
func main() {
var x interface{} =10
switch i := x.(type) {
case nil:
printString("x is nil") // type of i is type of x (interface{})
case int:
printInt(i) // type of i is int
case float64:
printFloat64(i) // type of i is float64
case func(int) float64:
printFunction(i) // type of i is func(int) float64
case bool, string:
printString("type is bool or string") // type of i is type of x (interface{})
default:
printString("don't know the type") // type of i is type of x (interface{})
}
}
还有一种t,ok:= x.(int)
有两个返回值,第一个是对应类型的值,第二个是bool类型的,类型判断是否正确。