golang學習總結

學習golang注意點:python

  1. 導的包必須使用;或者使用_未使用的包,做用是調用該包下的初始化方法。
  2. 局部變量聲明必須使用。
  3. go語言的包和java的類似,包名.變量訪問

1. 初識go語言

1.1 Hello World

package main

import "fmt"

func main() {
    fmt.Println("hello world");
}

1.2 go 數據類型

布爾:

var a bool = true
var b bool = false

整型:

整型分爲有符號和無符號的類型golang

8, 16 ,32 分別表明位數編程

int: 根據系統決定是32位還64位json

int8: 1個字節,-128~127 至關於java中的short;數組

int16: 2個字節,-215 ~ 215 -1網絡

int32: 4個字節 -231 ~231 - 1數據結構

int64: 8個字節-263 ~263 - 1閉包

uint : .....app

無符號整形都是取值0~216 - 1

var a int = -3
var b uint = 3 //uint類型不能夠爲負數

浮點型:

var a float32 = 100.0
var b float64 = 100.00 //默認

字符類型

golang中的字符使用的是字節保存的,本質就是一個int32類型

var a byte = 'a'
var b byte = 'c'
fmt.Print(a, "===", b)  //輸出的是該字節對應的字節碼: 97===99
fmt.Printf("%c === %c", a, b) // a === c

字符串型:

var str string = "hello world"
//多行字符串,不須要使用+來鏈接多行
var str2 string = `a 
        asda asdasdadsadasd `

複數類型:

complex64 是兩個float32組成 complex128兩個float64組成

var a complex64 = 10 + 3i
var b complex128= 10 + 3i //默認

相關操做

var v= complex(2 , 3) //構造1個複數, 
a := real(v) //返回複數實部 2
b := image(v) 返回複數虛部 3

rune類型:

// rune is an alias for int32 and is equivalent to int32 in all ways. It is
// used, by convention, to distinguish character values from integer values.

//int32的別名,幾乎在全部方面等同於int32
//它用來區分字符值和整數值
type rune = int32

1.3 變量常量

局部變量:

屬於函數或者方法;聲明以後必須使用

var a = 3;
var b int = 3;
c := 3

全局變量

b := 10 這種全局變量聲明是錯誤的

全局變量的概念:隸屬於,聲明以後能夠不使用

var a int
var (
    c int
    d string
)
var e = 3

常量

局部

const a = 3

全局

const a int = 10
const b  = 20
const (
    d int = 10
    e string = "ss"
    f = 30
)

1.5 字符串相關操做

golang中string底層是經過byte數組實現的,byte使用utf-8編碼標識的Unicode文本,每一個漢字佔3個字節

  1. 求長度
func strDemo() {
    fmt.Println(len("hello")) //5
    fmt.Println(len("中")) //3
    fmt.Println(len([]rune("中"))) //1, 正確獲取中文字符串長度
}
  1. 字符串遍歷
//對中文沒法支持
func strEach() {
    str := "hello world"
    for i := 0; i < len(str); i ++ {
        //fmt.Print(str[i] ,"\t") // 104    101 108 108 111 32  119 111 114 108 100
        //講字節編碼轉爲字符串輸出
        fmt.Printf("%c\t", str[i]) //h  e   l   l   o       w   o   r   l   d
    }
}
func strEach() {
    str := "hello world 中國"
    for i, s := range str {
         //0    h1  e2  l3  l4  o5   6  w7  o8  r9  l10 d11  12 中15 國
        fmt.Print(i, "\t", string(s))
    }
}

//這個能夠正確的輸出索引
func strEachRune() {
    str := "中國人民"
    for i, s := range []rune(str) {
        fmt.Println(i, string(s))
    }
}
  1. 其餘操做
str := "中國人民, hello world"
index := strings.Index(str, "國") //存在則 index > -1, 不然 == -1   此時index=-3
split := strings.Split(str, ",")
replace := strings.Replace(str, "o", "2", 1) //第三個參數標識替換幾個,小於0,則替換全部
result := strings.EqualFold("中國", "中國2") //不區分大小寫
fmt.Println("中國" == "中國H") //區分大小寫, 同strings.Compare()5

1.6 相互轉換

1.6.1 基本數據

golang基本數據數據之間的轉換可以使用公:T(i) 進行相互轉換

//數據之間的相互轉換
func transfer() {
    //
    var i int = 10
    var j float64 = 11.30
    x := float64(i)
    y := int(j)
    fmt.Print(x, "\t", y) //10  11
}

1.6.2 string <=> 基本數據類型

  1. 基本類型=>string

fmt.Sprintf(format string, param interface{})

func stringTrans() {
    var i int = 10
    var flag bool = true
    int_str := fmt.Sprintf("%d", i)
    bool_str := fmt.Sprintf("%t", flag)
    fmt.Println(int_str)
    fmt.Println(bool_str)
}

strconv

func stringStrco() {
    var i int = 10000
    var flag bool = true
    var price float64 = 130.32
    formatInt := strconv.FormatInt(int64(i), 10) //等價: strconv.Itoa(i)
    formatBool := strconv.FormatBool(flag)
    formatFloat := strconv.FormatFloat(price, 'f', 10, 64)
    fmt.Println(formatInt)
    fmt.Println(formatBool)
    fmt.Println(formatFloat)
}
  1. String=>基本數據類型
func strToBase() {
    str_flag := "true"
    str_age := "20"
    str_price := "20.33"
    flag, _ := strconv.ParseBool(str_flag)
    age, _ := strconv.ParseInt(str_age, 10, 64)
    age_int, _ := strconv.Atoi(str_age)
    price, _ := strconv.ParseFloat(str_price, 64)
    fmt.Println(flag)
    fmt.Println(age)
    fmt.Println(price)
    fmt.Println(age_int)
}

1.6.3 字節數組和字符串

func byteAndStr() {
    str := "hello world, 中國"
    data := []byte(str)
    s := string(data)
    fmt.Println(s)
    fmt.Println(data)
}

1.7 時間

  1. 獲取時間
func timeOperate() {
    cur := time.Now()
    curT := time.Now().Unix() //獲取時間戳
    fmt.Println(cur) //2019-01-30 20:40:16.410689 +0800 CST m=+0.000353772
    fmt.Println(curT) //1548852137
}
  1. 時間和字符串轉換
func formatTime() {
    format := time.Now().Format("2006-01-02 15:04:05")

    //時間戳轉時間
    var timestamp int64 = 1548852137
    unix := time.Unix(timestamp, 0).Format("2006-01-02 15:04:05")

    //字符串轉時間
    formatTimeStr := "2017-04-11 13:33:37"
    strToTime, _ := time.Parse("2006-01-02 15:04:05", formatTimeStr)

    fmt.Println(format) //2019-01-30 21:00:53
    fmt.Println(unix)
    fmt.Println(strToTime) //2017-04-11 13:33:37 +0000 UTC
}

1.8 複合數據類型

數組和切片(slice)之間的區別:

​ 數組:聲明的時候必須指定長度var arr [10]int,值類型,可是在java裏面數組是引用類型

​ Slice: 長度可變,不須要指定長度,引用類型

1. 數組

//數組的聲明
func createArray() {
    var books [3]string
    books[0] = "java"
    books[1] = "python"
    books[2] = "golang"

    names := [3]string{"lisi", "zhansan", "hand"}

    scores := [...]int{89, 59, 30, 100} //根據後面的內容決定長度

    fmt.Println(books)
    fmt.Println(names)
    fmt.Println(scores)
}

//數組的相關操做
func operateArray() {
    //數組長度
    scores := [...]int{89, 59, 30, 100}
    fmt.Println(len(scores))

    //數組遍歷
    for i := 0; i < len(scores); i++ {
        fmt.Print(scores[i], "\t")
    }

    fmt.Println()

    for index, value := range scores {
        fmt.Print(index, "==", value, "\t")
    }
}

2. slice

slice是一個比較複雜的數據結構,也就至關於Java裏面集合的概念,是一個可變長的數據

//最簡單的一種聲明方式
func createSlice() {
    var args []int
    args = make([]int, 10)
    args[0] = 1
    args[1] = 2
    args[2] = 3
    args[3] = 4
    args[4] = 5
    for index, value := range args {
        fmt.Println(index, value)
    }
}

經過數組定義一個切片

len 切片長度, 表示當前切片元素的個數

cap切片容量,表示切片能夠容納切片的個數,若是超出則報錯

func createSlice2() {
    arrays := [...]int{1, 2, 3, 4, 5}
    slice := arrays[1:4] //[2 3 4]
    fmt.Println(len(slice)) //3
    fmt.Println(cap(slice)) //4
    slice[1] = 10
    //這裏能夠解釋下圖
    fmt.Println(arrays) //[1 2 10 4 5]
    fmt.Println(slice) // [2 10 4]
}

這裏容量爲何是4?,如圖

append&copy函數

當append超出原來容量的時候,會擴展原來的容量爲原先的兩倍

//append
func appendFunc() {
    slice := make([]int, 2, 4)
    slice[0] = 1
    slice[1] = 1
    slice = append(slice, 2)
    slice = append(slice, 3)
    slice = append(slice, 4)
    fmt.Println(len(slice)) //5
    fmt.Println(cap(slice)) //8
}

//copy函數的用法
func copyFunc() {
    slice := make([]int, 2, 4)
    slice2 := make([]int, 2, 4)
    slice[0] = 1
    slice[1] = 1
    copy(slice2, slice) //至關於 slice2 := slice[:]
    fmt.Println(slice2) // [1 1]
}

3. map

map 數據結構和java的HashMap相似。

//建立一個map
func createMap() {
    var product map[string]interface{} //聲明
    product = make(map[string]interface{}) //初始化
    product["id"] = 1
    product["title"] = "口紅"
    product["price"] = 199.33
    fmt.Println(product)
}

//遍歷map
func mapForEach() {
    var product map[string]interface{} //聲明
    product = make(map[string]interface{}) //初始化
    product["id"] = 1
    product["title"] = "口紅"
    product["price"] = 199.33
    for key, value := range product {
        fmt.Println(key, value)
    }
}

1.9 golang面向對象

1. 結構體

go語言中的結構體和Java中的類很類似,包含屬性,方法等內容。首字母大寫對其餘包可見,首字母小寫只是對本包可見。

指針和值類型: 指針類型的方法能夠修改屬性的值,值類型的不能夠修改,

package main

import "fmt"

func main() {
    student := &Student{"zhansn", 24}
    fmt.Println(student.GetName())//zhansn
    student.SetName("lisi")
    fmt.Println(student.GetName()) //lisi
}

//對屬性小寫能夠封裝
type Student struct {
    name string
    age int
}

//定義結構體的方法GetName和SetName


func (this Student) GetName() string {
    return this.name
}

//這裏使用指針能夠改變屬性的內容
func (this *Student) SetName(name string) {
    this.name = name
}

2. 繼承

在go語言中結構體和結構體沒有繼承,而是經過組合的方式來獲取其餘結構體的方法。此時的Student可使用Person的全部屬性和方法,不管是否封裝。

package main

import "fmt"

func main() {
    student := &Student{}
    fmt.Println(student.GetName()) // ""
    student.SetName("lisi")
    fmt.Println(student.GetName()) //lisi
}

//對屬性小寫能夠封裝
type Student struct {
    Person
}
type Person struct {
    name string
    age int
}

//定義類型的方法
func (this Person) GetName() string {
    return this.name
}

//這裏使用指針能夠改變屬性的內容
func (this *Person) SetName(name string) {
    this.name = name
}

3. 接口

golang接口中沒有變量,只有方法。

對於java中的多態描述:重載和重寫兩種多態。可是在golang中沒法對方法進行重載,由於golang是一門面向函數編程的語言。因此golang能夠經過重寫來實現多態,並且是接口和子類之間的重寫。

package main

import "fmt"

func main() {
    ben := &Ben{"benchi"}
    ao := &Ao{"aodi"}
    ToString(ben)
    ToString(ao)
}

type Car interface {
    GetName() string
    SetName(name string)
}

func ToString(car Car) {
    fmt.Println(car.GetName())
}

type Ben struct {
    name string
}

func (ben Ben) GetName() string {
    return ben.name
}

func (ben *Ben) SetName(name string) {
    ben.name = name
}

type Ao struct {
    name string
}

func (this Ao) GetName() string {
    return this.name
}

func (this *Ao) SetName(name string) {
    this.name = name
}

4. 類型斷言

golang 類型斷言和java中的instanceof 關鍵字類似,可是又比這個關鍵字高級,好用,實現方式val.(T)

func main() {
    var x interface{}
    x = 4
    if y, ok := x.(int); ok {
        fmt.Println(y)
    }
}

斷言接口子類

package main

import "fmt"

func main() {
    ben := Ben{"benchi"}
    ao := Ao{"aodi"}
    ToString(ben)
    ToString(ao)
}

type Car interface {
    GetName() string
}

func ToString(car Car) {
    if ben, ok := car.(Ben); ok {
        fmt.Println(ben.GetName())
    } else if ao, ok := car.(Ao); ok {
        fmt.Println(ao.GetName())
    } else {
        fmt.Println("other type")
    }
}

type Ben struct {
    name string
}

func (ben Ben) GetName() string {
    return ben.name
}

type Ao struct {
    name string
}

func (this Ao) GetName() string {
    return this.name
}

以下代碼,有什麼問題呢?此時咱們使用指針類型是實現了接口notify的方法,那麼在SendNotify(u notify)中咱們必須使用子類的指針做爲參數傳遞到該函數,若是咱們使用值類型實現接口notify的方法,例如func (this user) Notify()這樣既可使用指針也可使用值傳遞參數。

package main

import "fmt"

func main() {
    u := &user{"hello"} //此時必須傳遞指針參數
    SendNotify(u)
}

type notify interface {
    Notify()
}

type user struct {
    name string
}

//指針實現接口
func (this *user) Notify() {
    fmt.Println(this.name)
}

func SendNotify(u notify) {
    u.Notify()
}

這是爲何呢?

對於一個方法method(param T) 能夠接受值類型指針類型的參數,method(param *T) 僅僅能夠接受指針類型的參數。

5. 閉包

java中有函數式編程,集合框架中有一個消費型函數forEach,咱們在golang中經過閉包實現該函數

package main

import "fmt"

func main() {
    data := []int{1,2,3,4,5}
    forEach(data, func(index int, value interface{}) {
        fmt.Println(index, value)
    })
}

func forEach(data []int, f func(int, interface{})) {
    for index, value := range data {
        f(index, value)
    }
}

2. golang 雜項

2.0 defer

defer會在函數或者方法結束前被調用,和Java中finally類似

func main() {
    /**
    first
    hello world
    defer is called
     */
    say()
}

func say() {
    fmt.Println("first")
    defer fmt.Println("defer is called")
    fmt.Println("hello world")
}

//因爲return了,因此return後面的語句不會被執行
func say2() {
    fmt.Println("first")
    return
    defer fmt.Println("defer is called")
    fmt.Println("hello world")
}

defer使用場景:錯誤處理,關閉資源,釋放鎖,後續會見到這些使用操做

2.1 錯誤處理

這裏訴說的錯誤處理和Java中的異常處理同樣,在java語言中錯誤處理通常都是try...catch…finally,而在golang語言中經過三個關鍵字對錯誤盡心處理:(defer recover) panic

  1. defer+recover來捕獲異常
func catchError() {
    defer func() {
        err := recover()
        if err != nil {
            fmt.Println("出現異常", err)
        }
    }()
    a := 10
    b := 0
    x := a / b
    fmt.Println(x)
}
  1. 自定義異常
func catchError() {
    //在這裏捕獲處理,若是不進行捕獲,則程序會崩潰
    defer func() {
        err := recover()
        if err != nil {
            fmt.Println("出現異常", err)
        }
    }()
    err := selfError()
    //向外拋出異常
    panic(err)
}

func selfError() error {
    return errors.New("自定義異常")
}

2.2 日誌

package main

import "log"

func main() {
    //  info:2019/02/04 16:47:25 LoggerDemo.go:6: message
    log.Println("message")
}

func init() {
    log.SetPrefix("info:")
    log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)
}
func main() {
    log.Println("message")
    //Fatalln執行以後調用:os.Exit(1), 退出程序,後續程序再也不執行
    log.Fatalln("打印日誌,程序退出")
    fmt.Println("還會執行嗎")
}

定製日誌記錄器

package logger

import (
    "log"
    "os"
    "io"
)

var (
    Debug *log.Logger  //僅僅輸出到控制檯
    Info *log.Logger
    Warning *log.Logger
    Error *log.Logger
)

const (
    logFlag = log.LstdFlags | log.Lshortfile
)

func init() {
    file, error := os.OpenFile("info.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
    if error != nil {
        panic(error)
    }
    Debug = log.New(os.Stdout, "debug:", logFlag)
    Info = log.New(io.MultiWriter(file, os.Stdout), "info:", logFlag)
    Warning = log.New(os.Stdout, "waring:", logFlag)
    Error = log.New(io.MultiWriter(file, os.Stderr), "error:", logFlag)
}

測試

package main

import "logger"

func main() {
    logger.Debug.Println("debug")
    logger.Info.Println("create a info log")
    logger.Error.Println("create a errr log")
}

2.3 IO流

package main

import (
    "os"
    "fmt"
    "bufio"
    "io"
    "io/ioutil"
)

func openFile() {
    file, err := os.Open("info.log")
    if err != nil {
        fmt.Println("文件錯誤", err)
    }
    defer file.Close()

    reader := bufio.NewReader(file)
    for {
        str, err := reader.ReadString('\n')
        if err == io.EOF { //表示讀取完畢
            break
        }
        fmt.Print(str)
    }
}

//讀取內容到內存中
func openFile2() {
    data, err := ioutil.ReadFile("info.log")
    if err != nil {

    }
    fmt.Print(string(data))
}

func writeFile() {
    file, err := os.OpenFile("hello.txt", os.O_WRONLY| os.O_CREATE | os.O_APPEND, 0666)
    if err != nil {
        fmt.Println("建立文件錯誤")
        return
    }
    defer file.Close()

    writer := bufio.NewWriter(file)
    for i := 0; i < 5; i++ {
        writer.WriteString("寫入數據:\n")
    }
    writer.Flush() //將緩衝區內容寫入到文件中

}

//判斷文件是否存在
func IsExist() {
    _, e := os.Stat("info2.log")
    if e != nil {
        exist := os.IsNotExist(e)
        fmt.Println(exist)
    }
}

2.5 json

package main

import (
    "encoding/json"
    "fmt"
    "time"
)

type Book struct {
    Title string
    Author string
    Publish time.Time
}


//序列化map
func serializeMap() {
    student := make(map[string]interface{})
    student["name"] = "閏土"
    student["age"] = 20
    student["class"] = "大一"
    bytes, err := json.Marshal(student)
    if err != nil {
        fmt.Println("序列化錯誤")
    }
    fmt.Println(string(bytes)) //{"age":20,"class":"大一","name":"閏土"}
}

//序列化結構體
func serializeStruct() {
    book := Book{"青春","itcloud", time.Now()}
    bytes, _ := json.Marshal(book)
    fmt.Println(string(bytes)) // {"Title":"青春","Author":"itcloud","Publish":"2019-02-05T11:14:51.094709+08:00"}
}

func deserializeMap() {
    var student map[string]interface{}
    data := `{"age":20,"class":"大一","name":"閏土"}`
    err := json.Unmarshal([]byte(data), &student)
    if err != nil {}
    fmt.Println(student)
}

func deserializeStruct() {
    var book Book
    bookStr := `{"Title":"青春","Author":"itcloud","Publish":"2019-02-05T11:14:51.094709+08:00"}`
    json.Unmarshal([]byte(bookStr), &book)
    fmt.Println(book)
}

2.6 網絡編程

1. TCP

客戶端

package main

import (
    "bufio"
    "fmt"
    "net"
    "os"
)

func main() {

    conn, _ := net.Dial("tcp", "127.0.0.1:8088")

    reader := bufio.NewReader(os.Stdin)
    line, _ := reader.ReadString('\n')

    n, _ := conn.Write([]byte(line))

    fmt.Println(n)

}

服務端

package main

import (
    "fmt"
    "net"
)

func main() {
    listener, err := net.Listen("tcp", "127.0.0.1:8088")
    if flag := Checkout(err, "監聽開啓錯誤"); !flag {
        return
    }
    defer listener.Close()

    for {
        fmt.Println("等待客戶端創建鏈接...")
        conn, err := listener.Accept()
        if flag :=  Checkout(err, "打開鏈接失敗"); flag {
            fmt.Printf("conn= %v, ip = %v\n", conn, conn.RemoteAddr().String())
        }
        go process(conn)

    }


}

func process (conn net.Conn) {
    defer conn.Close()
    for {
        buf := make([]byte, 1024)
        readLen, err := conn.Read(buf)
        if flag := Checkout(err, "讀取失敗"); !flag {
            return
        }
        fmt.Println(string(buf[:readLen]))
    }
}

func Checkout(err error, msg string) bool {
    if err != nil {
        fmt.Println(msg, err)
        return false
    }
    return true
}

2. http

func main() {
    http.HandleFunc("/echo", echo)
    http.ListenAndServe(":8080", nil)
}

func echo(w http.ResponseWriter, r *http.Request) {
    body, err := ioutil.ReadAll(r.Body)
    if err != nil {
        w.Write([]byte("get body error"))
        return
    }
    strlen, err := w.Write(body)
    if err != nil && strlen != len(body) {
        w.Write([]byte("write a error"))

    }
}
package main

import (
    "net/http"
    "time"
)

//自定義handler
func main() {
    myHandler := &SelfHandle{format: time.RFC1123}
    http.Handle("/time", myHandler)
    http.ListenAndServe(":8080", nil)
}

type SelfHandle struct {
    format string
}

func (h *SelfHandle) ServeHTTP(w http.ResponseWriter,  r *http.Request) {
    forTime := time.Now().Format(h.format)
    w.Write([]byte("time is " + forTime))
}

多路複用處理器

package main

import "net/http"

//多路複用處理器
func main() {
    mux := http.NewServeMux()
    mux.HandleFunc("/hello", hello)
    mux.HandleFunc("/world", world)
    server := &http.Server{Addr: ":8080", Handler: mux}
    server.ListenAndServe()
}

func hello(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("hello"))
}

func world(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("word"))
}
相關文章
相關標籤/搜索