GO基礎知識分享

[TOC]golang

GO基礎知識分享

兵長:喲,最近在幹啥呢api

胖sir:在看我以前的go基礎學習資料呢,回顧一下數組

兵長:那給我分享一下唄,我也想回顧回顧安全

胖sir:用你的小手指點開你的手機,我來傳給你數據結構

兵長:你信不信個人小手指能夠帶你飛整個峽谷 . . .併發

go語言的基本事項

  1. go run hello.go 直接運行,輸出結果(原理也是編譯後執行)
  2. go build hello.go 生成可執行程序,運行可執行程序,輸出結果
  3. 注意 go語言中花括號不能單獨佔一行,不然會報錯
package main

import "fmt"

func main(){ //go語言中此處的花括號不能單獨佔一行,不然會報錯
    fmt.Println("hello world")
}
  1. go語言一條語句佔一行,若是一行須要執行多個語句 使用 分號 隔開
  2. go語言的輸出語句有3種方式
    1. import "fmt" 後適用fmt.Println(x) -- 輸出
    2. println(x) -- 輸出
    3. fmt.Printf("%d",x) -- 格式化輸出

關鍵字

下面列舉了 Go 代碼中會使用到的 25 個關鍵字或保留字:app

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 個預約義標識符:ide

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
print println real recover string true uint uint8 uintptr

字符串的拼接和變量的定義方式

定義變量的三種方式函數

  1. 正常使用var定義變量
  2. 使用var定義變量,可是不定義類型,經過賦初值的方式,go編譯器自動識別
  3. 使用:=的方式來進行 新變量的定義,僅限於新變量 -- 適用於定義在函數內部
//字符串 可使用+ 進行拼接
    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循環的方式

  • 三種方式
  1. 相似C語言中的for
  2. 相似C語言中的while
  3. 死循環
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(){
//定義切片的方式
//一、使用var定義
    var s1 = []int{1,2,3};
    printInfo(s1);
//二、定義空slice
    var s2 []int
    printInfo(s2);
//三、使用:=定義
    ss := []int{3,4,5,6}
    printInfo(ss);

//四、使用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(){

//一、range 對於 數組、切片

    s := []string{"apple","pen"}
    for i,value := range s{
        fmt.Println(i,value)
    }

//二、對於字符串
    for i,value := range "hello"{
        fmt.Println(i,value)
    }

//三、range對於map集合
    m := map[string]string{"name":"xiaopang","age":"25"}
    for i,value := range m{
        fmt.Println(i,value)
    }

//四、佔位符_
    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))
}

以上爲本期所有內容,若有疑問能夠在評論區或後臺提出你的疑問,咱們一塊兒交流,一塊兒成長。

好傢伙要是文章對你還有點做用的話,請幫忙點個關注,分享到你的朋友圈,分享技術,分享快樂

技術是開放的,咱們的心態,更應是開放的。擁抱變化,向陽而生,努力向前行。

做者:小魔童哪吒

相關文章
相關標籤/搜索