golang入门
时间:2023-08-01 22:37:02
前言:
对go语言很感兴趣,所以简单学习一下是对的go语言初级入门
如果你想开始,你也可以看看个博主,他的是快速开始, 戳这里
golang语法香的一些地方:
-
极简单的部署方法:可直接编译成机器代码,不依赖其他库,直接运行。
-
静态类型语言在编译过程中可以发现大多数问题。
-
语言层面的并发:自然基因支持,充分利用多核
// Go 语言实现并发代码 func goFunc(i int) {
fmt.Println("goroutine ", i, " ...") } func main() {
for i := 0; i < 1000; i {
go goFunc(i) // 打开并发协程 } time.Sleep(time.Second) }
结果如下:
goroutine 9 ... goroutine 5 ... goroutine 0 ... goroutine 3 ... goroutine 2 ... goroutine 4 ... goroutine 8 ... goroutine 7 ... goroutine 6 ... goroutine 1 ...
-
强标准库:runtime 系统调度机制,高效 CG 垃圾回收,标准仓库丰富
“大厂” 领军:Google、facebook、Tencent、Baidu、七牛、字节 …
斐波那契数列算法不同语言 编译 运行 时间对比:
Golang 的应用场景
1.云计算基础设施领域:
代表项目:docker、kubernetes、etcd、consul、cloud flare CDN、七牛云存储 等。
代表项目:tidb、influxdb、 cockroach 等。
3、微服务
代表项目:go-kit、 micro、 monzo bank 的 typhon、bilibili 等。
4.互联网基础设施
代表项目:以太坊、以太坊、以太坊、以太坊、以太坊、以太坊、以太坊、以太坊、以太坊、以太坊、以太坊、以太坊、以太坊、以太坊、以太坊、以太坊、以太坊、以太坊、以太坊、以太坊、以太坊、以太坊、以太坊、以太坊、以太坊、以太坊、以太坊、以太坊、以太坊、以太坊、以太坊、以太坊、以太坊、以太坊、以太坊、以太坊、以太坊、以太坊、以太坊、以太坊、以太坊、以太坊、以太坊、以太坊、以太坊、以太坊、以太坊、以太坊、以太坊、以太坊、以太坊、以太坊、以太坊、以太坊、以太坊、以太坊、以太坊、以太坊、以太坊、以太坊、以太坊、以太坊、以太坊、以太坊、以太坊、以太坊、以太坊、以太坊、以太坊、以太坊、以太坊、以太坊、hyperledger 等
Golang 的不足
1.包管理,大部分包都是托管的 Github 上。
就像我们熟悉的 maven、npm 有专门的包管理组织;
托管在 Github 上述代码很容易受到作者个人操作的影响。
2.无泛化类型。
据说很快就会有。
3、所有 Exception 都用 Error 处理(有争议)。
4、对 C 降级处理不是无缝的,没有 C 降级到 asm 那么完美。(序列化问题)
go语言占位符:
占位符 | 说明 | 举例 | 输出 |
%v | 默认格式的相应值。 | Printf(“%v”, name) | {小小} |
% v | 在打印结构时,将添加字段名称 | Printf(“% v”, name) | {Name:小小} |
%#v | 相应值的Go语法表示 | Printf(“#v”, name) | main.Human{Name:“小小”} |
%T | 相应值的类型Go语法表示 | Printf(“%T”, name) | main.Human |
%% | 字面上的百分号,并非值的占位符 | Printf(%%) | % |
%t | true 或 false | Printf(“%t”, true) | TRUE |
%b | 二进制表示 | Printf(“%b”, 5) | 101 |
%c | Printf(“%c”, 0x4E2D) | 中 | |
%d | 十进制表示 | Printf(“%d”, 0x12) | 18 |
%o | 八进制表示 | Printf(“%d”, 10) | 12 |
%q | 单引号围绕的字符字面值,由Go语法安全地转义 | Printf(“%q”, 0x4E2D) | ‘中’ |
%x | 十六进制表示,字母形式为小写 a-f | Printf(“%x”, 13) | d |
%X | 十六进制表示,字母形式为大写 A-F | Printf(“%x”, 13) | D |
%U | Unicode格式:U+1234,等同于 “U+%04X” | Printf(“%U”, 0x4E2D) | U+4E2D |
%b | 无小数部分的,指数为二的幂的科学计数法, 与 strconv.FormatFloat 的 ‘b’ 转换格式一致。例如 -123456p-78 | ||
%e | 科学计数法,例如 -1234.456e+78 | Printf(“%e”, 10.2) | 1.02E+01 |
%E | 科学计数法,例如 -1234.456E+78 | Printf(“%e”, 10.2) | 1.02E+01 |
%f | 有小数点而无指数,例如 123.456 | Printf(“%f”, 10.2) | 10.2 |
%g | 根据情况选择 %e 或 %f 以产生更紧凑的(无末尾的0)输出 | Printf(“%g”, 10.20) | 10.2 |
%G | 根据情况选择 %E 或 %f 以产生更紧凑的(无末尾的0)输出 | Printf(“%G”, 10.20+2i) | (10.2+2i) |
%s | 输出字符串表示(string类型或[]byte) | Printf(“%s”, []byte(“Go语言”)) | Go语言 |
%q | 双引号围绕的字符串,由Go语法安全地转义 | Printf(“%q”, “Go语言”) | “Go语言” |
%x | 十六进制,小写字母,每字节两个字符 | Printf(“%x”, “golang”) | 676f6c616e67 |
%X | 十六进制,大写字母,每字节两个字符 | Printf(“%X”, “golang”) | 676F6C616E67 |
%p | 十六进制表示,前缀 0x | Printf(“%p”, &name) | 0x4f57f0 |
+ | 总打印数值的正负号;对于%q(%+q)保证只输出ASCII编码的字符。 | Printf(“%+q”, “中文”) | “\u4e2d\u6587” |
- | 在右侧而非左侧填充空格(左对齐该区域) | ||
# | 备用格式:为八进制添加前导 0(%#o) 为十六进制添加前导 0x(%#x)或 0X(%#X),为 %p(%#p)去掉前导 0x; 如果可能的话,%q(%#q)会打印原始 (即反引号围绕的)字符串; 如果是可打印字符,%U(%#U)会写出该字符的 Unicode 编码形式(如字符 x 会被打印成 U+0078 ‘x’)。 | Printf(“%#U”, ‘中’) | U+4E2D |
’ ’ | (空格)为数值中省略的正负号留出空白(% d); 以十六进制(% x, % X)打印字符串或切片时,在字节之间用空格隔开 | ||
0 | 填充前导的0而非空格;对于数字,这会将填充移到正负号之后 |
1)变量:
变量练习:
package main
import "fmt"
func main(){
//1.变量的声明
var age int
//2.变量的赋值
age = 18
//3.变量的使用
fmt.Println("age = ",age);
//声明和赋值可以合成一句:
var age2 int = 19
fmt.Println("age2 = ",age2);
//不可以在赋值的时候给与不匹配的类型
var num int = 12.56
fmt.Println("num = ",num);
}
一次性声明多个变量:
package main
import "fmt"
//全局变量:定义在函数外的变量
var n7 = 100
var n8 = 9.7
//设计者认为上面的全局变量的写法太麻烦了,可以一次性声明:
var (
n9 = 500
n10 = "netty"
)
func main(){
//定义在{}中的变量叫:局部变量
//第一种:变量的使用方式:指定变量的类型,并且赋值,
var num int = 18
fmt.Println(num)
//第二种:指定变量的类型,但是不赋值,使用默认值
var num2 int
fmt.Println(num2)
//第三种:如果没有写变量的类型,那么根据=后面的值进行判定变量的类型 (自动类型推断)
var num3 = "tom"
fmt.Println(num3)
//第四种:省略var,注意 := 不能写为 =
sex := "男"
fmt.Println(sex)
fmt.Println("------------------------------------------------------------------")
//声明多个变量:
var n1,n2,n3 int
fmt.Println(n1)
fmt.Println(n2)
fmt.Println(n3)
var n4,name,n5 = 10,"jack",7.8
fmt.Println(n4)
fmt.Println(name)
fmt.Println(n5)
n6,height := 6.9,100.6
fmt.Println(n6)
fmt.Println(height)
fmt.Println(n7)
fmt.Println(n8)
fmt.Println(n9)
fmt.Println(n10)
}
进制的介绍:
十进制整数,如:99, -500, 0
八进制整数,要求以 0 开头,如:015
十六进制数,要求 0x 或 0X 开头,如:0x15
二进制:要求0b或者0B开头,如:0b11
整数类型:
整数类型介绍:简单的说,就是用于存放整数值的,比如10,-45,6712等等。
有符号整数类型:
PS:127怎么算出来的?01111111 -->二进制 —》转为十进制: 12^6 + 12^5 + 12^4 + 12^3 + 12^2 + 12^1 + 1*2^0 = 64 + 32 + 16 + 8 + 4 + 2 + 1= 127
PS:-128怎么算出来的?10000000 —>二进制 —>一看就是个负数
10000000 --》负数的二进制减1:01111111取反:10000000 —》得到一个正数 2^7 = 128加负号:-128
无符号整数类型:
表数范围的边界计算:
11111111= 2^7+127 = 128 + 127 = 25500000000 = 0
其他整数类型:
PS:Golang的整数类型,默认声明为int类型
Ps:变量占用的字节数:
package main
import (
"fmt"
"unsafe"
)
func main() {
var num1 int8 = 110
fmt.Println(num1)
var num2 uint8 = 130
fmt.Println(num2)
var num3 = 28
//printf函数是格式化,%T就是填类型
fmt.Printf("num3 的类型是: %T", num3)
fmt.Println(unsafe.Sizeof(num3))
}
整数类型的选择:
这么多整数类型,使用的时候该如何选择呢?
Golang程序中整型变量在使用时,遵守保小不保大的原则,
即:在保证程序正确运行下,尽量使用占用空间小的数据类型
浮点类型:
【1】浮点类型介绍:
简单的说,就是用于存放小数值的,比如3.14、0.28、-7.19等等。
【2】浮点类型种类:
PS:底层存储空间和操作系统无关
PS:浮点类型底层存储:符号位+指数位+尾数位,所以尾数位只是存了 一个大概,很可能会出现精度的损失。
package main
import "fmt"
func main(){
//定义浮点类型的数据:
var num1 float32 = 3.14
fmt.Println(num1)
//可以表示正浮点数,也可以表示负的浮点数
var num2 float32 = -3.14
fmt.Println(num2)
//浮点数可以用十进制表示形式,也可以用科学计数法表示形式 E 大写小写都可以的
var num3 float32 = 314E-2
fmt.Println(num3)
var num4 float32 = 314E+2
fmt.Println(num4)
var num5 float32 = 314e+2
fmt.Println(num5)
var num6 float64 = 314e+2
fmt.Println(num6)
//浮点数可能会有精度的损失,所以通常情况下,建议你使用:float64
var num7 float32 = 256.000000916
fmt.Println(num7)
var num8 float64 = 256.000000916
fmt.Println(num8)
//golang中默认的浮点类型为:float64
var num9 = 3.17
fmt.Printf("num9对应的默认的类型为:%T",num9)
}
go的字符:
【1】Golang中没有专门的字符类型,如果要存储单个字符(字母),一般使用byte来保存。
【2】Golang中字符使用UTF-8编码
【3】ASCII码表:
左面是不可见字符 右面是可见字符
【4】查看UTF-8编码表:
http://www.mytju.com/classcode/tools/encode_utf8.asp
【5】代码实验:
package main
import "fmt"
func main(){
//定义字符类型的数据:
var c1 byte = 'a'
fmt.Println(c1)//97
var c2 byte = '6'
fmt.Println(c2)//54
var c3 byte = '('
fmt.Println(c3 + 20)//40
//字符类型,本质上就是一个整数,也可以直接参与运算,输出字符的时候,会将对应的码值做一个输出
//字母,数字,标点等字符,底层是按照ASCII进行存储。
var c4 int = '中'
fmt.Println(c4)
//汉字字符,底层对应的是Unicode码值
//对应的码值为20013,byte类型溢出,能存储的范围:可以用int
//总结:Golang的字符对应的使用的是UTF-8编码(Unicode是对应的字符集,UTF-8是Unicode的其中的一种编码方案)
var c5 byte = 'A'
//想显示对应的字符,必须采用格式化输出
fmt.Printf("c5对应的具体的字符为:%c",c5)
}
【6】转义字符:
转义字符:将后面的字母表示为特殊含义
package main
import "fmt"
func main(){
//练习转义字符:
//\n 换行
fmt.Println("aaa\nbbb")
//\b 退格
fmt.Println("aaa\bbbb")
//\r 光标回到本行的开头,后续输入就会替换原有的字符
fmt.Println("aaaaa\rbbb")
//\t 制表符
fmt.Println("aaaaaaaaaaaaa")
fmt.Println("aaaaa\tbbbbb")
fmt.Println("aaaaaaaa\tbbbbb")
//\"
fmt.Println("\"Golang\"")
}
bool类型:
【1】布尔类型也叫bool类型,bool类型数据只允许取值true和false
【2】布尔类型占1个字节。
【3】布尔类型适于逻辑运算,一般用于程序流程控制
【4】代码:
package main
import "fmt"
func main(){
//测试布尔类型的数值:
var flag01 bool = true
fmt.Println(flag01)
var flag02 bool = false
fmt.Println(flag02)
var flag03 bool = 5 < 9
fmt.Println(flag03)
}
string类型:
基本介绍:
【1】介绍:
字符串就是一串固定长度的字符连接起来的字符序列。对于字符串操作的 4 个包:bytes、strings、strconv、unicode
【2】字符串的使用:
package main
import "fmt"
func main() {
//1.定义一个字符串:
var s1 string = "你好全面拥抱Golang"
fmt.Println(s1)
//2.字符串是不可变的:指的是字符串一旦定义好,其中的字符的值不能改变
var s2 string = "abc"
//s2 = "def"
//s2[0] = 't'
fmt.Println(s2)
//3.字符串的表示形式:
//(1)如果字符串中没有特殊字符,字符串的表示形式用双引号
//var s3 string = "asdfasdfasdf"
//(2)如果字符串中有特殊字符,字符串的表示形式用反引号 ``
var s4 string = ` 左右同形,左小右大 上下同形,上小下大 左右等长,错位书写 左边小时要偏上 右边小时要下落 点下有竖,点竖直对 下有横竖横高竖低 下有撇点,撇高点低 package main import "fmt" func main(){ //测试布尔类型的数值: var flag01 bool = true fmt.Println(flag01) var flag02 bool = false fmt.Println(flag02) var flag03 bool = 5 < 9 fmt.Println(flag03) }`
fmt.Println(s4)
//4.字符串的拼接效果:
var s5 string = "abc" + "def"
s5 += "hijk"
fmt.Println(s5)
//当一个字符串过长的时候:注意:+保留在上一行的最后
var s6 string = "abc" + "def" + "abc" + "def" + "abc" + "def" + "abc" +
"def" + "abc" + "def" + "abc" + "def" + "abc" + "def" + "abc" + "def" +
"abc" + "def" + "abc" + "def" + "abc" + "def" + "abc" + "def" + "abc" +
"def" + "abc" + "def" + "abc" + "def" + "abc" + "def" + "abc" + "def" +
"abc" + "def" + "abc" + "def"
fmt.Println(s6)
}
(*)字符串的常用包使用展示:
简介:
- bytes 包操作
[]byte
。因为字符串是只读的,因此逐步构创建字符串会导致很多分配和复制,使用bytes.Buffer
类型会更高。 - strings 包提供 切割、索引、前缀、查找、替换 等功能。
- strconv 包提供 布尔型、整型数、浮点数 和对应字符串的相互转换,还提供了双引号转义相关的转换。
- unicode 包提供了 IsDigit、IsLetter、IsUpper、IsLower 等类似功能,用于给字符分类。
如果 string 中包含汉字,要注意:
- UTF-8 编码中,一个汉字需要 3 个字节,通过
len()
获取的是字符串占据的字节数。
str1 := "hello 世界"
fmt.Println(len(str1)) // 12
- 如果想要得到字符串本身的长度,可以将 string 转为 rune 数组再计算:
str2 := "hello 世界"
fmt.Println(len([]rune(str2))) // 8
字符串遍历
byte 是 uint8 的别名
rune 是 int32 的别名,相当于 Go 里面的 char
如果包含汉字,以下遍历方式会出现乱码:
str := "你好世界!"
for i := 0; i < len(str); i++ {
fmt.Printf("%c", str[i])
}
// ä½ å¥½ä¸çï¼%
- 解决方案1:转成 rune 切片再遍历
str := "你好世界!"
newStr := []rune(str)
for i := 0; i < len(newStr); i++ {
fmt.Printf("%c", newStr[i])
}
// 你好世界!
- 解决方案2:使用 range 来遍历
range 按照字符遍历,前面的 for 按照字节遍历
str := "你好世界123"
for index, value := range str {
fmt.Printf("index = %d value = %c\n", index, value)
}
index = 0 value = 你
index = 3 value = 好
index = 6 value = 世
index = 9 value = 界
index = 12 value = 1
index = 13 value = 2
index = 14 value = 3
strings包(简单操作)
字符串比较:使用 strings.Compare
比较两个字符串的字典序
strings.Compare("aaa", "bbb") // -1
strings.Compare("baa", "abb") // 1
strings.Compare("aaa", "aaa") // 0
查找函数:使用 strings.Index
查找字符串中子串的位置(第 1 个),不存在返回 -1
strings.Index("hello world", "o") // 4
类似的,使用 strings.LastIndex
查找字符串子串出现的最后一个位置,不存在返回 -1
strings.Index("hello world", "o") // 4
Count、Repeat:
使用 strings.Count
统计子串在整体中出现的次数:
strings.Count("abc abc abab abc", "abc") // 3
使用 strings.Repeat
将字符串重复指定次数:
strings.Repeat("abc", 3) // abcabcabc
Replace、Split、Join:
strings.Replace
实现字符串替换
str := "acaacccc"
// 局部替换 param3: 替换次数,< 0 则全部替换
strings.Replace(str, "a", "b", 2) // bcbacccc
strings.Replace(str, "a", "b", -1) // bcbbcccc
// 全部替换
strings.ReplaceAll(str, "a", "b") // bcbbcccc
strings.Split
实现字符串切割
str := "abc,bbc,bbd"
slice := strings.Split(str, ",")
fmt.Println(slice) // [abc bbc bbd]
strings.Join
实现字符串拼接
slice := []string{
"aab", "aba", "baa"}
str := strings.Join(slice, ",")
fmt.Println(str // aab,aba,baa
go语言好美啊!
bytes 包(buffer)
Buffer 是 bytes 包中定义的 type Buffer struct {...}
,Bufer 是一个变长的可读可写的缓冲区。buffer缓冲区好神奇!
创建缓冲器:bytes.NewBufferString
、bytes.NewBuffer
func main() {
buf1 := bytes.NewBufferString("hello")
buf2 := bytes.NewBuffer([]byte("hello"))
buf3 := bytes.NewBuffer([]byte{
'h', 'e', 'l', 'l', 'o'})
fmt.Printf("%v,%v,%v\n", buf1, buf2, buf3)
fmt.Printf("%v,%v,%v\n", buf1.Bytes(), buf2.Bytes(), buf3.Bytes())
buf4 := bytes.NewBufferString("")
buf5 := bytes.NewBuffer([]byte{
})
fmt.Println(buf4.Bytes(), buf5.Bytes())
}
hello,hello,hello
[104 101 108 108 111],[104 101 108 108 111],[104 101 108 108 111]
[] []
写入缓冲器:Write
、WriteString
、WriteByte
、WriteRune
、WriteTo
func main() { buf := bytes.NewBufferString("a") fmt.Printf("%v, %v\n", buf.String(), buf.Bytes()) // a, [97] buf.Write([]byte("b")) // Write buf.