共计 8487 个字符,预计需要花费 22 分钟才能阅读完成。
[TOC]
GO 基础知识分享
兵长:哟,最近在干啥呢
胖 sir:在看我之前的 go 根底学习材料呢,回顾一下
兵长:那给我分享一下呗,我也想回顾回顾
胖 sir:用你的小手指点开你的手机,我来传给你
兵长:你信不信我的小手指能够带你飞整个峡谷 . . .
go 语言的根本事项
- go run hello.go 间接运行,输入后果(原理也是编译后执行)
- go build hello.go 生成可执行程序,运行可执行程序,输入后果
- 留神 go 语言中花括号不能独自占一行,否则会报错
package main
import "fmt"
func main(){ //go 语言中此处的花括号不能独自占一行,否则会报错
fmt.Println("hello world")
}
- go 语言一条语句占一行,如果一行须要执行多个语句 应用 分号 隔开
- go 语言的输入语句有 3 种形式
-
- import “fmt” 后实用 fmt.Println(x) — 输入
- println(x) — 输入
- fmt.Printf(“%d”,x) — 格式化输入
关键字
上面列举了 Go 代码中会应用到的 25 个关键字或保留字:
break | default | func | interface | select |
---|---|---|---|---|
case | defer | go | map | struct |
chan | else | goto | package | switch |
const | fallthrough | if | range | type |
continue | for | import | return | var |
除了以上介绍的这些关键字,Go 语言还有 36 个预约义标识符:
append | bool | byte | cap | close | complex | complex64 | complex128 | uint16 |
---|---|---|---|---|---|---|---|---|
copy | false | float32 | float64 | imag | int | int8 | int16 | uint32 |
int32 | int64 | iota | len | make | new | nil | panic | uint64 |
println | real | recover | string | true | uint | uint8 | uintptr |
字符串的拼接和变量的定义形式
定义变量的三种形式
- 失常应用 var 定义变量
- 应用 var 定义变量,然而不定义类型,通过赋初值的形式,go 编译器自动识别
- 应用:= 的形式来进行 新变量的定义,仅限于新变量 — 实用于定义在函数外部
// 字符串 能够应用 + 进行拼接
fmt.Println("this is my func")
fmt.Println("hello ,wolrd" + "xiaozhuzhu")
// 定义变量
var name string="xiaomotong"
var age,tail int=24,170
fmt.Println(name, age , tail)
fmt.Println(name)
fmt.Println(age)
fmt.Println(tail)
// 定义变量的三种形式
//1
var a int = 1
fmt.Println(a)
//2 应用 var 定义变量,然而不定义类型,通过赋初值的形式,go 编译器自动识别
var b = "hello"
fmt.Println(b)
//3 应用:= 的形式来进行 新变量的定义,仅限于新变量
//:= 左侧如果没有申明新的变量,就产生编译谬误
c := 20
fmt.Println(c)
//c:=30 // 报错,因为 c 曾经不是新变量的
c=30 // 正确,是一个失常的赋值操作
fmt.Println(c)
c,d:=40,90 // 这样是非法的
fmt.Println(c,d)
因式分解的形式,仅仅实用于定义全局变量
// 因式分解的形式,仅仅实用于定义全局变量
var
(
g_a int = 1
g_b,g_c int=1,2
)
空白符
空白标识符 _ 也被用于摈弃值,如值 5 在:_, b = 5, 7 中被摈弃。
_ 实际上是一个只写变量,你不能失去它的值。这样做是因为 Go 语言中你必须应用所有被申明的变量,但有时你并不需要应用从一个函数失去的所有返回值。
// 空白符
_,e := 2,3
fmt.Println(e)
const 常量
- 定义 const 常量
// 定义 const 常量
const width,height = 10,5
var area int=width*height
fmt.Println("面积为", area) //50
- const 常量用作枚举
const(
unknow = 0
man = 1
woman = 2
)
println(unknow,man,woman) //0 1 2
- 常量能够用 len(), cap(), unsafe.Sizeof()函数计算表达式的值。常量表达式中,函数必须是内置函数,否则编译不过:
const(
a = "hello"
b = len(a)
c = unsafe.Sizeof(a)
)
println(a,b,c) //hello 5 16
iota 的用法
iota,非凡常量,能够认为是一个能够被编译器批改的常量。
iota 在 const 关键字呈现时将被重置为 0(const 外部的第一行之前),const 中每新增一行常量申明将使 iota 计数一次(iota 可了解为 const 语句块中的行索引)。
iota 能够被用作枚举值:
//itoa 的用法
const(
g_a = iota
g_b
g_c
g_d
)
const(
g_e = iota
g_f = "hello"
g_g
g_h = iota
g_i
)
const(
g_j = 1<<iota
g_k
g_l
g_m
)
println(g_a,g_b,g_c,g_d)
println(g_e,g_f,g_g,g_h,g_i)
println(g_j,g_k,g_l,g_m)
//0 1 2 3
//0 hello hello 3 4
//1 2 4 8
运算符
go 语言的运算符和 C 语言的运算符基本一致
Go 没有三目运算符,不能实用?:
算术运算符
关系运算符
逻辑运算符
位运算符
赋值运算符
其余运算符
语言条件语句
- if xxx
if xxx {...}
- if xxx {…} else{…}
if xxx{...}else{...}
- if xxx{… if xxx { …}}
if xxx{
if xxx {...}
...
}
- switch
package main
import "fmt"
func main(){
grade:= 90
if grade >= 90{println("优良")
}else if grade >=70 && grade <90{println("良好")
}else{println("差")
}
var x interface{} // 计算类型
switch i := x.(type){
case nil:
fmt.Printf("x 的类型 :%T\n",i)
case int:
fmt.Printf("x 是 int 型")
default:
println("未知")
}
}
-
select
相似于 C 语言中的 select,用于多路 IO 复用
for 循环的形式
- 三种形式
- 相似 C 语言中的 for
- 相似 C 语言中的 while
- 死循环
package main
import "fmt"
func main(){
// 相似 C 语言中的 for
var sum int
for i:=1;i<=10;i++{sum +=i}
fmt.Println(sum)
// 相似于 while
for sum >30{
sum -= 10
fmt.Println(sum)
}
// 死循环
for {...}
- For-each range 循环
//for-each range 循环的形式
name := []string{"qqq","yyy"}
for i,str:= range name{fmt.Printf("%d -- %s\n",i,str)
}
//0 -- qqq
//1 -- yyy
------------------------------------------------------------------------
str := []string{"北京", "天津", "山东"}
// 能够默认丢掉第二个返回值
for i := range str {fmt.Printf("%d -- %s\n", i, str[i])
}
函数
go 语言的函数,能够有多个返回值,其余和 C 语言没有什么区别
作用域
与 C 语言统一
- 局部变量
- 全局变量
- 函数形参
数组 & 切片
思维和 C 语言统一,数组是固定长度的
切片是动静扩容的,相似于 C ++ 的 vector
切片写法如下:
name := []string{"xiaomotong","pangsir"}
nums :=[]int{1,2,3,4,5,6}
指针
var ptr1 *int
二级指针
var a int
var ptr *int
var pptr **int
ptr = &a
pptr = &ptr
指针数组
var ptr [5]*int
构造体
go 语言中的构造体变量,和构造体指针,拜访构造体成员的时候,都是应用 点 (.) 来进行拜访,如下:
// 定义一个构造体
type info struct{
name string
age int
height int
}
// 应用
var stu info
stu.name = "xiaomotong"
stu.age = 24
stu.height = 170
fmt.Println(stu.name,stu.age,stu.height)
var stu2 *info = &stu
stu2.name = "pangsir"
stu2.age = 24
stu2.height = 160
fmt.Println(stu2.name,stu2.age,stu2.height)
切片 slice
Go 语言切片是对数组的形象。
Go 数组的长度不可扭转,在特定场景中这样的汇合就不太实用,Go 中提供了一种灵便,性能强悍的内置类型切片(“ 动静数组 ”), 与数组相比切片的长度是不固定的,能够追加元素,在追加时可能使切片的容量增大。
- 应用 var 定义
- 定义空 slice
- 应用:= 定义
- 应用 make 来定义 make([]type,len,cap)
- apend 和 copy 的应用
package main
/*
author:xiaomotong
file:slice
function:study slice for golang
*/
import "fmt"
func main(){
// 定义切片的形式
//1、应用 var 定义
var s1 = []int{1,2,3};
printInfo(s1);
//2、定义空 slice
var s2 []int
printInfo(s2);
//3、应用:= 定义
ss := []int{3,4,5,6}
printInfo(ss);
//4、应用 make 来定义 make([]type,len,cap)
s3 := make([]int,2,3)
printInfo(s3);
// 复制操作
s3[0] = 3
printInfo(s3);
// 笼罩整个 slice
s1 = s3
printInfo(s1);
//apend 和 copy 的应用
s3 = append(s3,6,7,8,9)
printInfo(s3);
// 扩容
s4 := make([]int,len(s3),cap(s3) * 3)
copy(s4,s3)
printInfo(s4);
//s[2:]
println(s4[1:])
println(s4[:4])
println(s4[1:3])
fmt.Printf("s4[1:] = %v \n",s4[1:])
fmt.Printf("s4[:4] = %v \n",s4[:4])
fmt.Printf("s4[1:3] = %v \n",s4[1:3])
}
func printInfo(s[]int){fmt.Printf("len = %d, cap = %d, slic = %v\n",len(s),cap(s),s);
}
范畴 Range
Go 语言中 range 关键字用于 for 循环中迭代数组 (array)、切片(slice)、通道(channel) 或汇合 (map) 的元素。
在数组和切片中它返回元素的 索引和索引对应的值 , 在汇合中返回 key-value 对。
- range 对于 数组、切片
- 对于字符串
- range 对于 map 汇合
- 占位符_
package main
/*
author:xiaomotong
file:range
function:study range for golang
*/
import "fmt"
func main(){
//1、range 对于 数组、切片
s := []string{"apple","pen"}
for i,value := range s{fmt.Println(i,value)
}
//2、对于字符串
for i,value := range "hello"{fmt.Println(i,value)
}
//3、range 对于 map 汇合
m := map[string]string{"name":"xiaopang","age":"25"}
for i,value := range m{fmt.Println(i,value)
}
//4、占位符_
sum := 0
nums := []int{1,2,3,4,5}
for _,value := range nums{sum += value}
fmt.Println(sum)
}
MAP 汇合
Map 是一种无序的键值对的汇合。Map 最重要的一点是通过 key 来疾速检索数据,key 相似于索引,指向数据的值。
Map 是一种汇合,所以咱们能够像迭代数组和切片那样迭代它。不过,Map 是无序的,咱们无奈决定它的返回程序,这是因为 Map 是应用 hash 表来实现的。
// 相似于 key-value 的模式
map[string]string
m := map[string]string{"name":"xiaozhu","age":"15"}
mm := make(map[string]string)
countryCapitalMap ["France"] = "巴黎"
countryCapitalMap ["Italy"] = "罗马"
countryCapitalMap ["Japan"] = "东京"
countryCapitalMap ["India"] = "新德里"
delete() 函数
delete() 函数用于删除汇合的元素, 参数为 map 和其对应的 key
delete(countryCapitalMap,"France")
递归函数
Go 语言反对递归。但咱们在应用递归时,开发者须要设置退出条件,否则递归将陷入有限循环中。
递归函数对于解决数学上的问题是十分有用的,就像计算阶乘,生成斐波那契数列等。
递归算阶乘
package main
import "fmt"
func fabulaxiaomotong(n uint 64) (result uint64){
if n>0 {return fabulaxiaomotong(n-1)*n
}
return 1
}
func main(){fmt.Println("result :",fabulaxiaomotong(15))
}
菲波拉契数列
func fabolaxiaomotong(n uint64)(result utin64){
if n<2{return n}else{return fabolaxiaomotong(n-2)+fabolaxiaomotong(n-1)
}
}
接口
Go 语言提供了另外一种 数据类型即接口,它把所有的具备共性的办法定义在一起,任何其余类型只有实现了这些办法就是实现了这个接口
package main
import "fmt"
// 接口
type phone interface {call()
show()}
type xiaomi struct {
name string
ads string
}
type huawei struct {
name string
ads string
}
// 接口实现
func (x xiaomi) call() {fmt.Println("phoneName :", x.name)
}
func (x xiaomi) show() {fmt.Println("advertisement :", x.ads)
}
func (h huawei) call() {fmt.Println("phoneName :", h.name)
}
func (h huawei) show() {fmt.Println("advertisement :", h.ads)
}
func main() {x := xiaomi{"mi note2", "for fire"}
x.call()
x.show()
h := huawei{"hw p40", "your better phone"}
h.call()
h.show()}
谬误
Go 语言通过内置的谬误接口提供了非常简单的错误处理机制。error 类型是一个接口类型,这是它的定义:
package main
import "fmt"
// 定义数据结构
type DivideError struct {
devidee int
devider int
}
// 错误处理实现 Error()接口
func (de *DivideError) Error() string {
strdata := `
error,divide is zero
dividee is %d
divider is zero
`
return fmt.Sprintf(strdata, de.devidee)
}
// 实现性能接口
func Divide(dividee int, divider int) (result int, errMsg string) {
if divider == 0 {data := DivideError{dividee, divider}
errMsg = data.Error()
return
} else {return dividee / divider, ""}
}
func main() {
a := 10
b := 0
result, err := Divide(a, b)
if err != "" {fmt.Println(err)
return
}
fmt.Printf("%d / %d == %d \n", a, b, result)
}
go 语言的并发
Go 语言反对并发,咱们只须要通过 go 关键字来开启 goroutine 即可。goroutine 是轻量级线程,goroutine 的调度是由 Golang 运行时进行治理的。goroutine 语法格局:
- go 的并发也是线程不平安的,须要加锁才平安
package main
import (
"fmt"
"time"
)
func say(s string) {
var i int
for i = 0; i < 5; i++ {time.Sleep(100 * time.Millisecond)
fmt.Println(s)
}
}
var num int = 0
//goroutine 是线程不平安的
func countNum() {
var i int
for i = 0; i < 10; i++ {time.Sleep(5 * time.Millisecond)
num++
}
}
func main() {//go say("hello")
//say("world")
go countNum()
countNum()
fmt.Println(num)
}
通道(channel)
- 通道(channel)是用来传递数据的一个数据结构。通道可用于两个 goroutine 之间通过传递一个指定类型的值来同步运行和通信。操作符 <- 用于指定通道的方向,发送或接管。如果未指定方向,则为双向通道。
-
- 留神:默认状况下,通道是不带缓冲区的。发送端发送数据,同时必须有接收端相应的接收数据。以下实例通过两个 goroutine 来计算数字之和,在 goroutine 实现计算后,它会计算两个后果的和:
- 通道能够设置缓冲区,通过 make 的第二个参数指定缓冲区大小
- Go 通过 range 关键字来实现遍历读取到的数据,相似于与数组或切片
package main
import "fmt"
// 不带缓冲的 通道
func getSum(s []int, c chan int) {
sum := 0
for _, value := range s {sum += value}
c <- sum
}
func getSum2(c chan int, n int) {
x, y := 0, 1
var i int
for i = 0; i < n; i++ {
c <- x
x, y = y, x+y
}
close(c) // 敞开通道
}
func main() {
// 不带缓冲的 通道
// s := []int{3, 5, -2, 3, 4, 7, 1, 1, 1}
// c := make(chan int)
// go getSum(s[:3], c)
// go getSum(s[3:6], c)
// go getSum(s[6:], c)
// x, y, z := <-c, <-c, <-c
// fmt.Println(x, y, z, x+y+z)
// 带缓冲的通道
c := make(chan int, 10)
go getSum2(c, cap(c))
for value := range c {fmt.Println(value)
}
}
本人调用别的包 / 本人的包
本人调用他人的包或者本人的包,如上目录构造
- 本人写的包名,要和目录名一样
- 应用 go mod 模块,执行 go mod init mystudy
mylib.go
package mylib
func Add(a, b int) int {return a + b}
main.go
package main
import (
"fmt"
"mystudy/mylib"
)
func main() {fmt.Println(mylib.Add(2, 3))
}
以上为本期全部内容,如有疑难能够在评论区或后盾提出你的疑难,咱们一起交换,一起成长。
好家伙要是文章对你还有点作用的话,请帮忙点个关注,分享到你的朋友圈,分享技术,分享高兴
技术是凋谢的,咱们的心态,更应是凋谢的。拥抱变动,背阴而生,致力向前行。
作者:小魔童哪吒