Go语言学习(一)
Go语言学习
GO的优势
极简单的部署方式
- 可直接编译成机器码
- 不依赖其他库
- 直接运行即可部署
静态类型的语言
- 编译的时候检查出来隐藏的大多数问题
语言层面的并发
- 天生的基因支持
- 充分的利用多核
强大的标准库
- runtime系统调度机制
- 高效的GC垃圾回收(3色标记和混合写屏障)
- 丰富的标准库(加解密 底层库 同步机制 网络通信 数据结构与算法等等)
简单易学
- 25个关键字
- c语言简洁基因 内嵌c语法支持
- 面向对象的特征(继承、多态、封装)
- 跨平台
大厂领军
- google facebook
- 腾讯 docker 百度 运维BFE 京东 云储存
- 哔哩哔哩 阿里巴巴 新浪 七牛 滴滴 字节 小米 美团
不足
- 包管理不完善
- 无泛化类型
- 所有的Exception都用error来处理
- 对c的降级处理,并非无缝,没有c降级到asm(汇编)那么完美(序列化问题)
GO语言的强项
-
云计算基础设施
docker、kubernetes、etcd、consul、cloudflare CDN、七牛云存储等 -
基础后端软件
-
微服务
-
互联网基础设施
以太坊、hyperledger等
GO语言的基本轮廓
package main
import "fmt"
func main() {
fmt.Println("Hello Go!")
}
//编译
go build Hello.go
./Hello
//或者
//编译并执行
go run Hello.go
//初始化项目
go mod init 项目名
变量
package main
import "fmt"
//声明全局变量 :=不实用
var gA int = 100
var gB string = "100"
func main() {
//============声明全局变量==================================
// 声明一个变量 默认值是0
var a int
fmt.Println("a=", a)
fmt.Printf("type of a=%T\n", a)
//声明一个变量 初始化值
var b int = 100
fmt.Println("b=", b)
fmt.Printf("type of a=%T\n", b)
var bb string = "abcd"
fmt.Printf("bb=%s,type of bb =%T\n", bb, bb)
//在数据初始化的时候,省去数据类型,通过值自动匹配相应的数据类型
var c = 100
fmt.Println("c=", c)
fmt.Printf("type of c=%T\n", c)
var cc string = "abcdefg"
fmt.Printf("bb=%s,type of bb =%T\n", cc, cc)
//===================都适用=====================================
//最常用的方法 省去var关键字 直接自动匹配
e := 100
fmt.Println("e=", e)
fmt.Printf("type of e=%T\n", e, e)
f := "abcd"
fmt.Println(f)
//声明多个变量
var gg, hh int = 100, 200
fmt.Println(gg, hh)
var kk, ll = 100, "abcd"
fmt.Println(kk, ll)
var (
vv int = 100
jj int = 200
mm string = "mmm"
zz bool = true
)
fmt.Println(vv, jj, mm, zz)
}
常量与iota
package main
import "fmt"
//常量在go语言中定义枚举类型
const (
name = "BearBrick0"
age1 = 22
sex = 1
height = 175
)
//可以在const() 添加一个关键字 iota 每行的iota 都会默认加1,第一行的iota的默认值是0
const (
num0 = iota
num1
num2
num3
num4
)
func main() {
//常量--只读属性
//常量赋值之后不能重新在对它赋值
const length = 100
const age int = 10
fmt.Println(length, ",", age)
fmt.Println(name, age1, sex, height)
fmt.Println(num0, num1, num2, num3, num4)
}
函数
package main
import "fmt"
func main() {
c := fool1("abc", 10)
fmt.Println(c)
d, e := fool2("abc", 2)
fmt.Println(d, e)
f, g := fool3("qwe", 12)
fmt.Println(f, g)
}
//函数返回一个值
func fool1(a string, b int) int {
fmt.Println(a)
fmt.Println(b)
c := 100
return c
}
//返回多个
func fool2(a string, b int) (int, int) {
fmt.Println(a)
fmt.Println(b)
return 66, 11
}
//指定形参
//func fool3(a string, b int) (r1,r2 int)
func fool3(a string, b int) (r1 int, r2 int) {
fmt.Println(a)
fmt.Println(b)
r1 = 12
r2 = 34
return r1, r2
}
init函数和import导包
在不同包 调用函数
在同一个包不同文件调用sayHello
//同包 -----》函数小写开头都是私有的方法
sayHello()
//在项目根目录编译
go build 绝对路径
//快速运行
go run /Users/wanglufei/Documents/GoStudy
1.2 在不同包不同文件调用SayHello
//不同包----》函数大写开头都是共有的方法
note.SayHello()
//在项目根目录编译
go build 绝对路径
//单个主文件
go build 路径
//在项目根目录也可以
go build 路径
Modules包管理
大项目结构
golang-standards/project-layout: Standard Go Project Layout (github.com)
小项目地址
screego/server: screen sharing for developers https://screego.net/ (github.com)
注释
和Java差不多。官方建议单行注释。
转义字符
package main
import (
"fmt"
)
func main() {
fmt.Println("str := \"c:\\pprof\\main.exe\"")
}
基本数据类型
Golang中所有的值类型变量常量都会在声明是被分配内存空间并被赋默认值。
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
。
整型
整型分为以下两个大类: 按长度分为:int8
、int16
、int32
、int64
对应的无符号整型:uint8
、uint16
、uint32
、uint64
其中,uint8
就是我们熟知的byte
型,int16
对应C语言中的short
型,int64
对应C语言中的long
型。
浮点型
Go语言支持两种浮点型数:float32
和float64
。这两种浮点型数据格式遵循IEEE 754
标准: float32
的浮点数的最大范围约为3.4e38
,可以使用常量定义:math.MaxFloat32
。 float64
的浮点数的最大范围约为 1.8e308
,可以使用一个常量定义:math.MaxFloat64
。
复数
complex64`和`complex128
复数有实部和虚部,complex64
的实部和虚部为32位,complex128
的实部和虚部为64位。
布尔值
Go语言中以bool
类型进行声明布尔型数据,布尔型数据只有true(真)
和false(假)
两个值。
注意:
布尔类型变量的默认值为false。
Go 语言中不允许将整型强制转换为布尔型.
布尔型无法参与数值运算,也无法与其他类型进行转换。
字符串
Go语言中的字符串以原生数据类型出现,使用字符串就像使用其他原生数据类型(int、bool、float32、float64 等)
一样。 Go 语言里的字符串的内部实现使用UTF-8编码。 字符串的值为双引号("
)中的内容,可以在Go语言的源码中直接添加非ASCII
码字符,例如:
s1 := "hello"
s2 := "你好"
//多行字符串
s1 := `第一行
第二行
第三行
`
fmt.Println(s1)
反引号间换行将被作为字符串中的换行,但是所有的转义字符均无效,文本将会原样输出。
字符串的常用操作
方法 | 介绍 |
---|---|
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类型
组成每个字符串的元素叫做“字符”,可以通过遍历或者单个获取字符串元素获得字符。 字符用单引号(’)包裹起来,如:
var a := '中'
var b := 'x'
Go 语言的字符有以下两种:
uint8类型,或者叫 byte 型,代表了ASCII码的一个字符。
rune类型,代表一个 UTF-8字符。
当需要处理中文、日文或者其他复合字符时,则需要用到rune
类型。rune
类型实际是一个int32
。 Go 使用了特殊的 rune
类型来处理 Unicode
,让基于 Unicode
的文本处理更为方便,也可以使用 byte
型进行默认字符串处理,性能和扩展性都有照顾
// 遍历字符串
func traversalString() {
s := "pprof.cn博客"
for i := 0; i < len(s); i++ { //byte
fmt.Printf("%v(%c) ", s[i], s[i])
}
fmt.Println()
for _, r := range s { //rune
fmt.Printf("%v(%c) ", r, r)
}
fmt.Println()
}
输出:
112(p) 112(p) 114(r) 111(o) 102(f) 46(.) 99(c) 110(n) 229(å) 141() 154() 229(å) 174(®) 162(¢)
112(p) 112(p) 114(r) 111(o) 102(f) 46(.) 99(c) 110(n) 21338(博) 23458(客)
因为UTF8编码下一个中文汉字由3~4
个字节组成,所以我们不能简单的按照字节去遍历一个包含中文的字符串,否则就会出现上面输出中第一行的结果。
字符串底层是一个byte数组,所以可以和[]byte类型相互转换。字符串是不能修改的 字符串是由byte字节组成,所以字符串的长度是byte字节的长度。 rune类型用来表示utf8字符,一个rune字符由一个或多个byte组成。
修改字符串
要修改字符串,需要先将其转换成[]rune或[]byte
,完成后再转换为string
。无论哪种转换,都会重新分配内存,并复制字节数组。
func changeString() {
s1 := "hello"
// 强制类型转换
byteS1 := []byte(s1)
byteS1[0] = 'H'
fmt.Println(string(byteS1))
s2 := "博客"
runeS2 := []rune(s2)
runeS2[0] = '狗'
fmt.Println(string(runeS2))
}
类型转换
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)
}
指针
区别于C/C++中的指针,Go语言中的指针不能进行偏移和运算,是安全指针。要搞明白Go语言中的指针需要先知道3个概念:指针地址、指针类型和指针取值。
Go语言中的指针
Go语言中的函数传参都是值拷贝,当我们想要修改某个变量的时候,我们可以创建一个指向该变量地址的指针变量。传递数据使用指针,而无须拷贝数据。类型指针不能进行偏移和运算。Go语言中的指针操作非常简单,只需要记住两个符号:&
(取地址)和*
(根据地址取值)。
指针地址和指针类型
每个变量在运行时都拥有一个地址,这个地址代表变量在内存中的位置。Go语言中使用&
字符放在变量前面对变量进行“取地址”操作。 Go语言中的值类型(int、float、bool、string、array、struct)
都有对应的指针类型,如:*int、*int64、*string
等。
取变量指针的语法如下:
ptr := &v // v的类型为T
其中:
v:代表被取地址的变量,类型为T
ptr:用于接收地址的变量,ptr的类型就为*T,称做T的指针类型。*代表指针。
举个例子:
func main() {
a := 10
b := &a
fmt.Printf("a:%d ptr:%p\n", a, &a) // a:10 ptr:0xc00001a078
fmt.Printf("b:%p type:%T\n", b, b) // b:0xc00001a078 type:*int
fmt.Println(&b) // 0xc00000e018
}
我们来看一下b := &a
的图示:
指针取值
在对普通变量使用&
操作符取地址后会获得这个变量的指针,然后可以对指针使用*
操作,也就是指针取值,代码如下。
func main() {
//指针取值
a := 10
b := &a // 取变量a的地址,将指针保存到b中
fmt.Printf("type of b:%T\n", b)
c := *b // 指针取值(根据指针去内存取值)
fmt.Printf("type of c:%T\n", c)
fmt.Printf("value of c:%v\n", c)
}
输出如下:
type of b:*int
type of c:int
value of c:10
总结: 取地址操作符&和取值操作符*
是一对互补操作符,&
取出地址,*
根据地址取出地址指向的值。
变量、指针地址、指针变量、取地址、取值的相互关系和特性如下:\
1.对变量进行取地址(&)操作,可以获得这个变量的指针变量。
2.指针变量的值是指针地址。
3.对指针变量进行取值(*)操作,可以获得指针变量指向的原变量的值。
指针传值示例:
func modify1(x int) {
x = 100
}
func modify2(x *int) {
*x = 100
}
func main() {
a := 10
modify1(a)
fmt.Println(a) // 10
modify2(&a)
fmt.Println(a) // 100
}
fmt格式字符(fmt verbs)
通用
整数
浮点数
布尔
字符串或byte切片
指针
本文来自博客园,作者:{BearBrick0},转载请注明原文链接:{https://www.cnblogs.com/bearbrick0}