Golang Snippets

raku · · 529 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

Golang

install

Getting Started - The Go Programming Language

首先下载得到 go1.11.2.linux-amd64.tar.gz

tar -C /usr/local -xzf go$VERSION.$OS-$ARCH.tar.gz

之后在 /usr/local 有个 go1.11.2 的目录

然后加入 path

export PATH=$PATH:/usr/local/goxxx/bin
export GOROOT=/usr/local/goxxx

Go都是值传递 不用指针函数中得到的就是一个copy

Array 是值传递 但是map slice channel 表现的很像是引用

First, and most important, does the method need to modify the receiver? If it does, the receiver must be a pointer. (Slices and maps act as references)

https://golang.org/doc/faq#references

Error

errors.New("")

JSON

map to string

    fmt.Println("fill map::", rsFillmap)
    if jsonByte, err := json.Marshal(rsElemap); err != nil {
        fmt.Println(err)
    } else {
        fmt.Println("..............", string(jsonByte))
    }

string to map

    jsonStr := `
    {
        "name":"liangyongxing",
        "age":12
    }
    `
    var mapResult map[string]interface{}
    if err := json.Unmarshal([]byte(jsonStr), &mapResult); err != nil {
        t.Fatal(err)
    }

Slice

仅声明 需要用make 但是初始化不用 所以一般用最后一种

arr := make([]int, 5)

// 实际上这里是一个slice
args := []string{"what", "ever", "you", "like"}


b := []string{}  //这样也可以创建一个slice  没有必要make

关于数组的类型

    mmm := map[string]interface{}{}
    data := `{"key": [{"haha": {"xixi": 10}}]}`
    json.Unmarshal([]byte(data), &mmm)

    if rs, ok := mmm["key"].([]map[string]interface{}); ok {
        fmt.Println("ok", rs)
    }else{
        fmt.Println("not ok")
    }
    //not ok


    if rs, ok := mmm["key"].([]interface{}); ok {
        fmt.Println("ok", rs)
        if rs2, ok2 := rs[0].(map[string]interface{}); ok2 {
            fmt.Println("ok2", rs2)
        }

    }else{
        fmt.Println("not ok")
    }   
  //ok2 map[haha:map[xixi:10]]
  //ok [map[haha:map[xixi:10]]]

第一个if 结果是not ok 原因是go只知道key下面是一个数组 起元素都是interface{} 类型 不能知道这里的元素是 map[string]interface{}
所以这么断言是not ok

map init

仅声明不赋值 需要用make
初始化的同时赋值 可以用后一种

    m := make(map[string]int)
    m["haha"] = 1
    
    mm := map[string]int{
        "Bell Labs": 1,
        "MMM":2,
    }
    fmt.Printf("%+v  %+v", m, mm)


Map range / Map iterate


for k, v := range m {
    fmt.Printf("k=%v, v=%v\n", k, v)
}

删除某个key

var sessions = map[string] chan int{};
delete(sessions, "moo");

map to struct

go - Converting map to struct - Stack Overflow

import "github.com/mitchellh/mapstructure"

mapstructure.Decode(myData, &result)

map key exsits

if _, ok := map[key]; ok {
   //存在
}

Type And Value

fmt.Println(reflect.TypeOf(b), reflect.ValueOf(b).Kind())



var x float64 = 3.4
fmt.Println("value:", reflect.ValueOf(x).String())

Exception Handing

func Log(t interface{}) {
    defer func() {
        if p := recover(); p != nil {
            fmt.Printf("panic recover!!!!!!!!!!!!!! p: %v", p)
            debug.PrintStack()
        }
    }()

    s := reflect.ValueOf(&t).Elem()
    typeOfT := s.Type()

    for i := 0; i < s.NumField(); i++ {
        f := s.Field(i)
        fmt.Printf("%d: %s %s = %v\n", i,
            typeOfT.Field(i).Name, f.Type(), f.Interface())
    }
}


String to Byte (byte to string)

[]byte(str)

string(bytes)

String To Int/Float


#string to int  
int,err:=strconv.Atoi(string)  
#string to int64  
int64, err := strconv.ParseInt(string, 10, 64)  

#int to string  
string:=strconv.Itoa(int)  
#int64 to string  
string:=strconv.FormatInt(int64,10)
还可以使用 Sprint 更通用 对于 float 也可以处理
fmt.Sprint(5.03)


#string到 float
iiii, _ := strconv.ParseFloat("32.23", 64)

float to int
int(float)

int to float
float(int)  float64(xxx)

[]int to string

strings.Join 只能接收 []string

strings.Trim(strings.Replace(fmt.Sprint(a), " ", delim, -1), "[]")

:=

:= 左边有新变量即可

#string到int  
int,err:=strconv.Atoi(string)  
#string到int64  
int64, err := strconv.ParseInt(string, 10, 64)  
#int到string  
string:=strconv.Itoa(int)  
#int64到string  
string:=strconv.FormatInt(int64,10)  

defer

PS 即使return defer 也会执行

func f() (result int) {

  defer func() {
    result++
  }()
  return 0
}
上面函数返回1,因为defer中添加了一个函数,在函数返回前改变了命名返回值的值。是不是很好用呢。但是,要注意的是,如果我们的defer语句没有执行,那么defer的函数就不会添加,如果把上面的程序改成这样:

func f() (result int) {

  return 0
  defer func() {
    result++
  }()
  return 0
}
上面的函数就返回0了,

if else 作用域

if 中声明的变量 在同一层else中也有效


    if bytes, err := json.Marshal(bizResp); err != nil {
        errMsg := fmt.Sprintf("fail to encode biz-resp : %v", bizResp)
        log.Error(errMsg)
        return nil, errors.New(errMsg)
    } else {
        refType := reflect.TypeOf(bizResp)
        w := &clueThrift.ThriftProtocolResponseWrapper{
            BaseResp:       &base.BaseResp{},
            JsonData:       string(bytes),
            OriginTypeName: refType.PkgPath() + "/" + refType.Name(),
        }
        return w, nil
    }

[]interface 数组赋值传参

Frequently Asked Questions (FAQ) - The Go Programming Language

当我们把一个string的slice 试图赋值给 一个interface的slice的时候
cannot use arr (type []string) as type []interface {}

    sss := []string{"xxx"}
    AA(sss)


func A(pp []interface{}){
    fmt.Println(pp)
}

可以这么做 (在作为参数传递时尤其如此) (PS 这是比较trick的做法)

  dest := []interface{}{}
    queries :=[]interface{}{}
    queries = append(queries, instanaceIds)
    dest = queries

断言

v := varI.(T)    //T是你要将接口转换的类型   // unchecked type assertion
varI 必须是一个接口变量,否则编译器会报错:

再看一个断言的例子

package main

import "fmt"
import "reflect"

type Xixi struct{
    A string
}


func main() {
    test(Xixi{A:"aaa"})
    testSlice([]Xixi{Xixi{A:"aaa"}, Xixi{A:"abb"}, Xixi{A:"acc"}})
}

func test(any interface{}){
    v := reflect.ValueOf(any)
    fmt.Printf("%+v  %+v\n", v, any)  //{A:aaa}  {A:aaa} //但是此时并不能 v.A  //因为go并不知道这究竟是哪种类型的数据
    if realV, ok := any.(Xixi); ok {
        fmt.Printf("%+v %+v ...\n", realV, realV.A)
    }
} 

func testSlice(any interface{}){
    v := reflect.ValueOf(any) //可以将any识别出是 [] //此时就可以循环了
    for i := 0; i < v.Len(); i++ {
        fmt.Printf("%+v\n", v.Index(i))
    }   
    
    //当然可以用断言一步到位
    if realV, ok := any.([]Xixi); ok{
        fmt.Println(len(realV), realV[0]) //3 {aaa}
    }else{
        fmt.Println("err")
    }
}

将interface{} 还原成原来实参(reflect)

Range a interface that holds a slice (or map)

当一个interface{} 里实际存着是一个slice的时候 如何range这个interface{} 呢
这里不是最好的办法 最好的方式是用断言

package main

import "fmt"
import "reflect"

func main() {
    data := []string{"one","two","three"}
    test(data)
    moredata := []int{1,2,3}
    test(moredata)
    ddd := make(map[int]string)
    ddd[1]= "xixi"
    test(ddd)
} 

func test(t interface{}) {
  switch reflect.TypeOf(t).Kind() {
    case reflect.Slice:
        s := reflect.ValueOf(t)

        for i := 0; i < s.Len(); i++ {
            fmt.Println(s.Index(i))
        }
      case reflect.Map:
        v := reflect.ValueOf(t)
        for _, key := range v.MapKeys() {
            strct := v.MapIndex(key)
            fmt.Println(key.Interface(), strct.Interface())
        }
    }
}


枚举类型实现


type ModelField int8

const (
    NULL          ModelField = iota
    AdvId
    InstanceId
    Name
    ComponentType
    CreateTime
    Status
    IsDel
    LotteryPool
    // ......
)

fmt.Print("id::", InstanceId, AdvId)  //得到 2 和 1

当然了 ModelField = iota 也可以替换成 int = itoa
这样写成 type 有个好处就是可以为这个类型增加一个方法

作用域

如果一个type 定义在func 中 那么只有这个func 才能使用这个type 外面并不能访问

打印指针

    a1 := AA{}
    a2 := AA{}
    a1.A = A{Ha:"xx"}
    fmt.Printf("... %p ... %p", &a1, &a2)

修改map中的值

map里是struct等复杂的对象 是不可以被直接修改的
比如
map[key] = A{}
然后又想 map[key].xx = xx
这样不行哦

很多时候要把map中的元素传到另一个func 中去修改 那么就要传指针 然而

https://github.com/golang/go/issues/11865
spec: can take the address of map[x]
也就是说不能够 &map[key]

那怎么办? 干脆在创建map的时候就用value的指针 而不是 value

    s := make(map[string]*Student)
    s["chenchao"] = &Student{
        Name:"chenchao",
        Id:111,
    }
    s["chenchao"].Id = 222

为基础类型增加方法(自定义 Int)


type Int int

func (i Int) Add(j Int) Int {
  return i + j
}

func main() {
  i := Int(5)
  j := Int(6)
  fmt.Println(i.Add(j))
  fmt.Println(i.Add(j) + 12)
}


不定长参数

函数接收一个不定长参数
和ES6有些不同的是
golang中
…XXX 是将多个item 合并到一个[]
XXX… 是打散[]

但是ES6中 形参 …xxx 是将多个item合并到xxx 比如function a(…xxx){}
如果 …xxx 这样的写法作为实参 就是打散 a(…xxx)

type Xixi struct{
    A string
}


func main() {
    f := func() interface{} {
        return 1
    }
    
    
    test(1, "wowo", Xixi{A: "aia"}, f)
}

func test(haha ...interface{}) {
    //haha 是一个[]  数组OR slice
    fmt.Println(reflect.TypeOf(haha)) //[]interface {}  
    fmt.Printf("%+v \n", haha) //[1 wowo 0x108f470] 
    fmt.Printf("%+v\n", reflect.ValueOf(haha[2])) //{A:aia}
    test2(haha) //得到 1  注意这样传下去 是把整个[]传到下一个函数了 
    test2(haha...) //把[]打散作为多个实参 得到4  //注意这里和ES6语法上的不同
}
func test2(xixi ...interface{}){
    fmt.Printf("%+v\n", len(xixi))
}

注意和ES6的区别

var s = (...haha) => {
    console.log(haha)
    arr = []
    arr = arr.concat(...haha)
    console.log(arr)
    s2(...haha)
}

var s2 = (...xixi) => {
    console.log(xixi)
}

s(1,2,3)

//=======================================
var xxx = [1,2,3,4]
function vvv(a,b,c,d){
console.log(a,b,c,d)
}
vvv(...xxx) //打散


interface的继承

golang实际上是通过组合实现的继承
Golang中的面向对象继承

struct 可以嵌套 struct
struct 可以嵌套 interface{}
interface 也可以嵌套 interface{}

go test

首先待测文件命名要是 xxx_test.go
需要进入到待测文件所在目录

go test -v -test.run Test_service_ListSites  (Testxxx 是待测的方法)
package listing

import (
    "testing"

    "github.com/stretchr/testify/assert"
)

func Test_service_ListSites(t *testing.T) {
    assert := assert.New(t)
    assert.True(true)
}

for range

  第一个参数是idx
    for _, p := range lotterInstanceData.Prize{
        p.AdvId = advId
    }

error and panic

在go里面 错误和异常是不同的
错误是自己手动创建出来的一个类型 异常就像其他语言需要try起来的部分


func funcA() error {
    defer func() {
        if p := recover(); p != nil {
            fmt.Printf("panic recover! p: %v\n", p)
            
        }
    }()
    return funcB()
}

func funcB() error {
    // simulation
    // panic("foo")
    return errors.New("!funb erroR!")
}

func test() {
    err := funcA()
    if err == nil {
        fmt.Printf("test err is nil\\n")
    } else {
        fmt.Printf("test err is %v\\n", err)
    }
}


func main() {
    test()
}

json to map

json to map 之后 数值类型都是float64

    mmm := map[string]interface{}{}
    data := `{"key": 10}`
    json.Unmarshal([]byte(data), &mmm)
    fmt.Printf("\n %+v \n", reflect.TypeOf(mmm["key"]))
  //float64

struct简写 property

type server struct {
    *app.App
}
相当于
type server struct {
    App *app.App
}

在同一个目录里有多个main函数

文件开头加上 // +build OMIT

dlv build

go build -o ./cmd/insight/dlv -gcflags "all=-N -l" ./cmd/insight/main.go

然后
dlv --listen=:2345 --headless=true --api-version=2 exec ./dlv
此时会等待 goland 的debug连接

点开虫子图标,就启动辣


**#!/usr/bin/env bash**
CURDIR=**$***(pwd)*
*echo*$CURDIR
*rm*./cmd/meteor-api/dlv
*go*build -o ./cmd/meteor-api/dlv -gcflags "all=-N -l" ./cmd/meteor-api/main.go
*cd***$**{CURDIR}/cmd/meteor-api/
*dlv*--listen=:2345 --headless=true --api-version=2 exec ./dlv


time format

fmt.Println(time.Now().Format("2006-01-02 15:04:05"))

// Y. M .D
thisMonth.AddDate(0, 0, -1).Format(DATE_FORMAT)

theTime.Unix() //转化为时间戳 类型是int64

go mod 1.11

Modules · golang/go Wiki · GitHub

默认 GO111MODULE 的值是 auto

如果你的项目在 go path 下 但是仍然希望使用新的包管理
需要设置

set -x GO111MODULE on

需要go mod init YOUR_MOD_NAME 新建一个go.mod

go build go get go run 等 go 命令会更新 go.mod 文件 (也是在GO111MODULE on 的情况下)

GO111MODULE on 的情况下才能使用 go mod vendor

dep

如果是 go1.11之前的 推荐使用 dep 包管理


dep ensure -add xxx@master

rand

(100) //产生0-100的随机整数

匿名字段

type Human struct {
    name string
    age int
    weight int
}

 

type Student struct {
    Human  // 匿名字段,那么默认Student就包含了Human的所有字段
    speciality string
}

litter 方便好用的 print

import "github.com/sanity-io/litter"

var (
    Dump  = litter.Dump
    Sdump = litter.Sdump
)

函数是一等公民

type A struct {
    Count func(c int) int
}
// 这样是表示在 A 类型中有一个 property Count 它是一个函数
// 然后这样赋值
c := A{
    Count: func(c int) int { return 12 },
}


嵌套结构体初始化

type Account struct {
    Id     uint32
    Name   string
    Nested struct {
        Age uint8
    }
}

//方法1  不推荐  太麻烦  而且容易出错
account := &Account{
        Id:   10,
        Name: "jim",
        Nested: struct {
            Age uint8
        }{
            Age: 20,
        },
    }

//方法2  推荐
acc ;= new Account()
acc.Nested.Age = 20
OR
acc := Account{}
acc.Nested.Age = 29


enum

go 没有枚举关键字 但是可以通过 const + itoa 来实现
itoa + 1 表示从1 开始

    type State int
    const (
        Phone State = iota + 1
        Form
        MapSearch
    )

  const (
      Haha int = 5
  )


switch


    type State int
    const (
        Phone State = iota + 1
        Form
        MapSearch
    )

    day := State(1)
    
    switch day {
    case Phone:
        fmt.Print(day)
    default:
        fmt.Print(0)
    }

获取当前程序所在目录

func getCurrentFilePath() string {

    dir, err := os.Getwd()
    if err != nil {
        logs.Debug("current file path err %+v", err)
    }
    fmt.Printf("current dir : %+v", dir)

    return dir
}


Ticker

Go by Example: Timers and Tickers

package main

import "time"

func main() {
    timer := time.NewTimer(time.Second * 2)
    <- timer.C  //will block until has value
    println("Timer expired")
}


package main

import "time"
import "fmt"
var ticker *time.Ticker 
func main() {
    ticker = time.NewTicker(time.Millisecond * 100)
    go func() {
        for {
            select {
            case rs,ok := <-ticker.C:
                fmt.Println("Tick at",ok, rs)
            }

        }
    }()
    time.Sleep(time.Millisecond * 1500)
    ticker.Stop()
    fmt.Println("Ticker stopped")
}


    timeChan := time.NewTimer(time.Second).C
    
    tickChan := time.NewTicker(time.Millisecond * 400).C
    
    doneChan := make(chan bool)
    go func() {
        time.Sleep(time.Second * 2)
        doneChan <- true
    }()
    
    for {
        select {
        case <- timeChan:
            fmt.Println("Timer expired")
        case <- tickChan:
            fmt.Println("Ticker ticked")
        case <- doneChan:
            fmt.Println("Done")
            return
      }
    }

go func() 并行

func UnblockGet(requestUrl string) chan string {
    resultChan := make(chan string)
    go func() {
        request := httplib.Get(requestUrl)
        content, err := request.String()
        if err != nil {
            content = "" + err.Error()
        }
        resultChan <- content
    } ()
    return resultChan
}

go regexp

    pat := `(((abc.)def.)ghi)`
    src := `abc-def-ghi abc+def+ghi`

    fmt.Println(regexp.MatchString(pat, src))
    // true <nil>

    fmt.Println(regexp.QuoteMeta(pat))

go slice join

import strings
stringFiles := strings.Join(fileSlice[:], ",")


//Back to Slice again

import strings
fileSlice := strings.Split(stringFiles, ",")

reverse slice

package main

import (
    "fmt"
    "reflect"
)

func reverse(s []interface{}) {
    for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
        s[i], s[j] = s[j], s[i]
    }
}

func reverseAny(s interface{}) {
    n := reflect.ValueOf(s).Len()
    swap := reflect.Swapper(s)
    for i, j := 0, n-1; i < j; i, j = i+1, j-1 {
        swap(i, j)
    }

}

func main() {
    s := []interface{}{1, "2", uint(3), byte(4), float64(5)}
    reverse(s)
    fmt.Println(s)
    reverseAny(s)
    fmt.Println(s)
}


还可以使用https://github.com/ahmetb/go-linq 这个库
这个库似乎虽然是linq 但有一些slice的功能

http req resp

方法1 不推荐 resp.Body 只能被读一次

resp, err := http.Post(url, “application/json”, bytes.NewBuffer([]byte(sql)))
json.NewDecoder(resp.Body).Decode(&respData)

方法2 ioUtil

req, err := http.NewRequest("GET", url, nil)
req.Header.Add("X-Orange-Caller", "ad.tetris.site_server")
resp, err := client.Do(req)
body, err := ioutil.ReadAll(resp.Body)
defer resp.Body.Close()
logs.Debug(string(body))

buf

resp, err := http.Post(url, "application/json", bytes.NewBuffer([]byte(sql)))

buf := new(bytes.Buffer)
buf.ReadFrom(resp.Body)
s := buf.String()



有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:raku

查看原文:Golang Snippets

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

529 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传