目录
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
SayHello
//不同包----》函数大写开头都是共有的方法
note.SayHello()
//在项目根目录编译
go build 绝对路径
//单个主文件
go build 路径
//在项目根目录也可以
go build 路径
Modules包管理
大项目结构
小项目地址
注释
和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
nilNULL
整型
int8int16int32int64uint8uint16uint32uint64
uint8byteint16shortint64long
浮点型
float32float64IEEE 754float323.4e38math.MaxFloat32float641.8e308math.MaxFloat64
复数
complex64`和`complex128
complex64complex128
布尔值
booltrue(真)false(假)
注意:
布尔类型变量的默认值为false。
Go 语言中不允许将整型强制转换为布尔型.
布尔型无法参与数值运算,也无法与其他类型进行转换。
字符串
(int、bool、float32、float64 等)"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字符。
runeruneint32runeUnicodeUnicodebyte
// 遍历字符串
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(客)
3~4
字符串底层是一个byte数组,所以可以和[]byte类型相互转换。字符串是不能修改的 字符串是由byte字节组成,所以字符串的长度是byte字节的长度。 rune类型用来表示utf8字符,一个rune字符由一个或多个byte组成。
修改字符串
[]rune或[]bytestring
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语言中的指针
&*
指针地址和指针类型
&(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
}