go語(yǔ)言基礎(chǔ)知識(shí)
go語(yǔ)言的基本事項(xiàng)
- go run hello.go 直接運(yùn)行,輸出結(jié)果(原理也是編譯后執(zhí)行)
- go build hello.go 生成可執(zhí)行程序抄腔,運(yùn)行可執(zhí)行程序烦却,輸出結(jié)果
- 注意 go語(yǔ)言中花括號(hào)不能單獨(dú)占一行脖岛,否則會(huì)報(bào)錯(cuò)
package main
import "fmt"
func main(){ //go語(yǔ)言中此處的花括號(hào)不能單獨(dú)占一行澎蛛,否則會(huì)報(bào)錯(cuò)
fmt.Println("hello world")
}
go語(yǔ)言一條語(yǔ)句占一行啡彬,如果一行需要執(zhí)行多個(gè)語(yǔ)句 使用 分號(hào) 隔開(kāi)
go語(yǔ)言的輸出語(yǔ)句有3種方式
- import "fmt" 后適用fmt.Println(x) -- 輸出
- println(x) -- 輸出
- fmt.Printf("%d",x) -- 格式化輸出
關(guān)鍵字
下面列舉了 Go 代碼中會(huì)使用到的 25 個(gè)關(guān)鍵字或保留字:
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 |
除了以上介紹的這些關(guān)鍵字压真,Go 語(yǔ)言還有 36 個(gè)預(yù)定義標(biāo)識(shí)符:
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定義變量杆煞,但是不定義類(lèi)型魏宽,通過(guò)賦初值的方式,go編譯器自動(dòng)識(shí)別
- 使用:=的方式來(lái)進(jìn)行 新變量的定義决乎,僅限于新變量 -- 適用于定義在函數(shù)內(nèi)部
//字符串 可以使用+ 進(jìn)行拼接
fmt.Println("this is my func")
fmt.Println("hello ,wolrd" + "xiaozhuzhu")
//定義變量
var name string="qingbing"
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定義變量队询,但是不定義類(lèi)型,通過(guò)賦初值的方式构诚,go編譯器自動(dòng)識(shí)別
var b = "hello"
fmt.Println(b)
//3 使用:=的方式來(lái)進(jìn)行 新變量的定義蚌斩,僅限于新變量
//:= 左側(cè)如果沒(méi)有聲明新的變量,就產(chǎn)生編譯錯(cuò)誤
c := 20
fmt.Println(c)
//c:=30 //報(bào)錯(cuò)范嘱,因?yàn)閏已經(jīng)不是新變量的
c=30 //正確送膳,是一個(gè)正常的賦值操作
fmt.Println(c)
c,d:=40,90 //這樣是合法的
fmt.Println(c,d)
因式分解的方式,僅僅適用于定義全局變量
//因式分解的方式丑蛤,僅僅適用于定義全局變量
var
(
g_a int = 1
g_b,g_c int=1,2
)
空白符
空白標(biāo)識(shí)符 _ 也被用于拋棄值叠聋,如值 5 在:_, b = 5, 7 中被拋棄。
_ 實(shí)際上是一個(gè)只寫(xiě)變量受裹,你不能得到它的值碌补。這樣做是因?yàn)?Go 語(yǔ)言中你必須使用所有被聲明的變量,但有時(shí)你并不需要使用從一個(gè)函數(shù)得到的所有返回值棉饶。
//空白符
_,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()函數(shù)計(jì)算表達(dá)式的值脑慧。常量表達(dá)式中,函數(shù)必須是內(nèi)置函數(shù)砰盐,否則編譯不過(guò):
const(
a = "hello"
b = len(a)
c = unsafe.Sizeof(a)
)
println(a,b,c) //hello 5 16
iota的用法
iota,特殊常量坑律,可以認(rèn)為是一個(gè)可以被編譯器修改的常量岩梳。
iota 在 const關(guān)鍵字出現(xiàn)時(shí)將被重置為 0(const 內(nèi)部的第一行之前)囊骤,const 中每新增一行常量聲明將使 iota 計(jì)數(shù)一次(iota 可理解為 const 語(yǔ)句塊中的行索引)。
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
運(yùn)算符
go語(yǔ)言的運(yùn)算符和C語(yǔ)言的運(yùn)算符基本一致
Go 沒(méi)有三目運(yùn)算符冀值,不能適用?:
算術(shù)運(yùn)算符
關(guān)系運(yùn)算符
邏輯運(yùn)算符
位運(yùn)算符
賦值運(yùn)算符
其他運(yùn)算符
語(yǔ)言條件語(yǔ)句
- 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("優(yōu)秀")
}else if grade >=70 && grade <90{
println("良好")
}else{
println("差")
}
var x interface{} //計(jì)算類(lèi)型
switch i := x.(type){
case nil:
fmt.Printf(" x 的類(lèi)型 :%T\n",i)
case int:
fmt.Printf("x 是 int 型")
default:
println("未知")
}
}
-
select
類(lèi)似于C語(yǔ)言中的select也物,用于多路IO復(fù)用
for循環(huán)的方式
- 三種方式
- 類(lèi)似C語(yǔ)言中的for
- 類(lèi)似C語(yǔ)言中的while
- 死循環(huán)
package main
import "fmt"
func main(){
//類(lèi)似C語(yǔ)言中的for
var sum int
for i:=1;i<=10;i++{
sum +=i
}
fmt.Println(sum)
//類(lèi)似于while
for sum >30{
sum -= 10
fmt.Println(sum)
}
//死循環(huán)
for {
...
}
- For-each range 循環(huán)
//for-each range 循環(huán)的方式
name := []string{"qqq","yyy"}
for i,str:= range name{
fmt.Printf("%d -- %s\n",i,str)
}
//0 -- qqq
//1 -- yyy
------------------------------------------------------------------------
str := []string{"北京", "天津", "山東"}
//可以默認(rèn)丟掉第二個(gè)返回值
for i := range str {
fmt.Printf("%d -- %s\n", i, str[i])
}
函數(shù)
go語(yǔ)言的函數(shù),可以有多個(gè)返回值列疗,其余和C語(yǔ)言沒(méi)有什么區(qū)別
作用域
與C語(yǔ)言一致
- 局部變量
- 全局變量
- 函數(shù)形參
數(shù)組&切片
思想和C語(yǔ)言一致滑蚯,數(shù)組是固定長(zhǎng)度的
切片是動(dòng)態(tài)擴(kuò)容的,類(lèi)似于C++的vector
寫(xiě)法如下:
name := []string{"qingbing","yongchao"}
nums :=[]int{1,2,3,4,5,6}
指針
var ptr1 *int
二級(jí)指針
var a int
var ptr *int
var pptr **int
ptr = &a
pptr = &ptr
指針數(shù)組
var ptr [5]*int
結(jié)構(gòu)體
go語(yǔ)言中的結(jié)構(gòu)體變量抵栈,和結(jié)構(gòu)體指針告材,訪問(wèn)結(jié)構(gòu)體成員的時(shí)候,都是使用 點(diǎn)(.)來(lái)進(jìn)行訪問(wèn)古劲,如下:
//定義一個(gè)結(jié)構(gòu)體
type info struct{
name string
age int
height int
}
//使用
var stu info
stu.name = "qingbing"
stu.age = 24
stu.height = 170
fmt.Println(stu.name,stu.age,stu.height)
var stu2 *info = &stu
stu2.name = "yongchao"
stu2.age = 24
stu2.height = 160
fmt.Println(stu2.name,stu2.age,stu2.height)
切片slice
Go 語(yǔ)言切片是對(duì)數(shù)組的抽象斥赋。
Go 數(shù)組的長(zhǎng)度不可改變,在特定場(chǎng)景中這樣的集合就不太適用产艾,Go中提供了一種靈活疤剑,功能強(qiáng)悍的內(nèi)置類(lèi)型切片("動(dòng)態(tài)數(shù)組"),與數(shù)組相比切片的長(zhǎng)度是不固定的,可以追加元素闷堡,在追加時(shí)可能使切片的容量增大隘膘。
- 使用var定義
- 定義空slice
- 使用:=定義
- 使用make來(lái)定義 make([]type,len,cap)
- apend 和 copy的使用
package main
/*
author:qingbing
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來(lái)定義 make([]type,len,cap)
s3 := make([]int,2,3)
printInfo(s3);
//復(fù)制操作
s3[0] = 3
printInfo(s3);
//覆蓋整個(gè)slice
s1 = s3
printInfo(s1);
//apend 和 copy的使用
s3 = append(s3,6,7,8,9)
printInfo(s3);
//擴(kuò)容
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 語(yǔ)言中 range 關(guān)鍵字用于 for 循環(huán)中迭代數(shù)組(array)倦零、切片(slice)误续、通道(channel)或集合(map)的元素。
在數(shù)組和切片中它返回元素的索引和索引對(duì)應(yīng)的值扫茅,在集合中返回 key-value 對(duì)蹋嵌。
- range 對(duì)于 數(shù)組、切片
- 對(duì)于字符串
- range對(duì)于map集合
- 占位符_
package main
/*
author:qingbing
file:range
function:study range for golang
*/
import "fmt"
func main(){
//1葫隙、range 對(duì)于 數(shù)組栽烂、切片
s := []string{"apple","pen"}
for i,value := range s{
fmt.Println(i,value)
}
//2、對(duì)于字符串
for i,value := range "hello"{
fmt.Println(i,value)
}
//3恋脚、range對(duì)于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 是一種無(wú)序的鍵值對(duì)的集合。Map 最重要的一點(diǎn)是通過(guò) key 來(lái)快速檢索數(shù)據(jù)糟描,key 類(lèi)似于索引怀喉,指向數(shù)據(jù)的值。
Map 是一種集合船响,所以我們可以像迭代數(shù)組和切片那樣迭代它躬拢。不過(guò)躲履,Map 是無(wú)序的,我們無(wú)法決定它的返回順序聊闯,這是因?yàn)?Map 是使用 hash 表來(lái)實(shí)現(xiàn)的工猜。
//類(lèi)似于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() 函數(shù)
delete() 函數(shù)用于刪除集合的元素, 參數(shù)為 map 和其對(duì)應(yīng)的 key
delete(countryCapitalMap,"France")
遞歸函數(shù)
Go 語(yǔ)言支持遞歸。但我們?cè)谑褂眠f歸時(shí)菱蔬,開(kāi)發(fā)者需要設(shè)置退出條件篷帅,否則遞歸將陷入無(wú)限循環(huán)中。
遞歸函數(shù)對(duì)于解決數(shù)學(xué)上的問(wèn)題是非常有用的拴泌,就像計(jì)算階乘魏身,生成斐波那契數(shù)列等。
遞歸算階乘
package main
import "fmt"
func fabulaqi(n uint 64) (result uint64){
if n>0 {
return fabulaqi(n-1)*n
}
return 1
}
func main(){
fmt.Println("result : ",fabulaqi(15))
}
菲波拉契數(shù)列
func fabolaqi(n uint64)(result utin64){
if n<2{
return n
}else{
return fabolaqi(n-2)+fabolaqi(n-1)
}
}
接口
Go 語(yǔ)言提供了另外一種數(shù)據(jù)類(lèi)型即接口弛针,它把所有的具有共性的方法定義在一起叠骑,任何其他類(lèi)型只要實(shí)現(xiàn)了這些方法就是實(shí)現(xiàn)了這個(gè)接口
package main
import "fmt"
//接口
type phone interface {
call()
show()
}
type xiaomi struct {
name string
ads string
}
type huawei struct {
name string
ads string
}
//接口實(shí)現(xiàn)
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()
}
錯(cuò)誤
Go 語(yǔ)言通過(guò)內(nèi)置的錯(cuò)誤接口提供了非常簡(jiǎn)單的錯(cuò)誤處理機(jī)制。error類(lèi)型是一個(gè)接口類(lèi)型削茁,這是它的定義:
package main
import "fmt"
//定義數(shù)據(jù)結(jié)構(gòu)
type DivideError struct {
devidee int
devider int
}
//錯(cuò)誤處理實(shí)現(xiàn)Error()接口
func (de *DivideError) Error() string {
strdata := `
error,divide is zero
dividee is %d
divider is zero
`
return fmt.Sprintf(strdata, de.devidee)
}
//實(shí)現(xiàn)功能接口
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語(yǔ)言的并發(fā)
Go 語(yǔ)言支持并發(fā)宙枷,我們只需要通過(guò) go 關(guān)鍵字來(lái)開(kāi)啟 goroutine 即可。goroutine 是輕量級(jí)線程茧跋,goroutine 的調(diào)度是由 Golang 運(yùn)行時(shí)進(jìn)行管理的慰丛。goroutine 語(yǔ)法格式:
- go的并發(fā)也是線程不安全的,需要加鎖才安全
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)是用來(lái)傳遞數(shù)據(jù)的一個(gè)數(shù)據(jù)結(jié)構(gòu)瘾杭。通道可用于兩個(gè) goroutine 之間通過(guò)傳遞一個(gè)指定類(lèi)型的值來(lái)同步運(yùn)行和通訊诅病。操作符 <- 用于指定通道的方向,發(fā)送或接收粥烁。如果未指定方向贤笆,則為雙向通道。
- 注意:默認(rèn)情況下讨阻,通道是不帶緩沖區(qū)的芥永。發(fā)送端發(fā)送數(shù)據(jù),同時(shí)必須有接收端相應(yīng)的接收數(shù)據(jù)钝吮。以下實(shí)例通過(guò)兩個(gè) goroutine 來(lái)計(jì)算數(shù)字之和埋涧,在 goroutine 完成計(jì)算后,它會(huì)計(jì)算兩個(gè)結(jié)果的和:
通道可以設(shè)置緩沖區(qū)奇瘦,通過(guò) make 的第二個(gè)參數(shù)指定緩沖區(qū)大小
Go 通過(guò) range 關(guān)鍵字來(lái)實(shí)現(xiàn)遍歷讀取到的數(shù)據(jù)棘催,類(lèi)似于與數(shù)組或切片
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) //關(guān)閉通道
}
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)
}
}
自己調(diào)用別的包/自己的包
自己調(diào)用別人的包或者自己的包,如上目錄結(jié)構(gòu)
- 自己寫(xiě)的包名耳标,要和目錄名一樣
- 使用go mod 模塊 醇坝,執(zhí)行 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))
}
以上為本期全部?jī)?nèi)容,如有疑問(wèn)可以在評(píng)論區(qū)或后臺(tái)提出你的疑問(wèn)次坡,我們一起交流呼猪,一起成長(zhǎng)呀袱。
好家伙要是文章對(duì)你還有點(diǎn)作用的話,請(qǐng)幫忙點(diǎn)個(gè)關(guān)注郑叠,分享到你的朋友圈,分享技術(shù)明棍,分享快樂(lè)
技術(shù)是開(kāi)放的乡革,我們的心態(tài),更應(yīng)是開(kāi)放的摊腋。擁抱變化沸版,向陽(yáng)而生,努力向前行兴蒸。
作者:小魔童哪吒