shownb / shownb.github.com

shownb.github.io
shownb.github.io
5 stars 1 forks source link

一坑未平,一坑又起,踩坑go #13

Open shownb opened 6 years ago

shownb commented 6 years ago

不要用apt-get install 安装,如果安装了,用这个反安装apt-get purge golang-go go的安装 查看最新版 https://golang.org/dl/ 不同版本,不同系统,不同arch都可以。然后设置一下PATH让系统找到go的bin旧可以了。 tar -C /usr/local -xzf go$VERSION.$OS-$ARCH.tar.gz

curl https://dl.google.com/go/go1.10.3.linux-amd64.tar.gz -o 1.tar.gz
tar -C /usr/local -xzf 1.tar.gz
echo "export PATH=$PATH:/usr/local/go/bin" >> .bashrc
source .bashrc

添加 /usr/local/go/bin 到PATH环境变量: 全局添加/etc/profile 或者 $HOME/.profile

export PATH=$PATH:/usr/local/go/bin

还有就是工作目录workspace,默认是$HOME/go,你不喜欢也可以自己改变 编辑.bashrc或者.bash_profile

export GOPATH=$HOME/zfile/go

让他生效

source ~/.bash_profile

编译 for Mac

CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build main.go

交叉编译

 env GOOS=linux go build -ldflags "-s -w" main.go
 env GOOS=linux GOARCH=arm go build -ldflags "-s -w" main.go

表达式 是由数字、算符、数字分组符号(括号)、变量和常量等以能求得数值的有意义排列方法所得的组合。 函数签名 函数参数、返回值以及它们的类型被统称为函数签名。

变量声明

  1. var a int (其实有默认值,是a=0)
  2. var a = 1 (其实go会根据右边的值,判断a的类型。)
  3. a := 1 (在函数内使用 相当于var a =)

具体参考 http://www.wklken.me/posts/2014/03/02/02-type-var-const.html

类型

byte 是uint8的别名 rune 是int32的别名 字符串是bytes的集合

函数

如果一个函数有多个返回值,那么这些返回值必须用()括起来。

func calc(input float64) (float64,float64) {
}

指针

Go 具有指针.指针保存了变量的内存地址. 类型 *T 是指向类型 T 的值的指针。其零值是 nil 。

 var p *int

& 符号会生成一个指向其作用对象的指针。

i := 42
p = &I

* 符号表示指针指向的底层的值。

fmt.Println(*p) // 通过指针 p 读取 i
*p = 21         // 通过指针 p 设置 i
package main
import "fmt"

type User struct {
    Id int
    Name string
}
func main(){
    i := 100
    var p *int = &i  //指针就是保存内存地址的,&的意思就是去取i的内存地址

    println(*p)   //而这里的*号,就是去取指针p的内存地址里面的值

    up := &User{1, "Jack"}
    up.Id = 100  //直接取指针对象成员
    fmt.Println(up)

    u2 := *up  //拷贝对象
    u2.Name = "Tom"
    fmt.Println(up, u2)
}

golang的goroutine是如何实现的? https://www.zhihu.com/question/20862617

[5]int{1,2,3} []int{1,2,3}就变成数组和切片了

数组

数组是具有相同 唯一类型 的一组已编号且长度固定的数据项序列 声明的格式是 var identifier [len]type

var arrAge = [5]int{18, 20, 15, 22, 16}
var arrLazy = [...]int{5, 6, 7, 8, 22}
//... 可同样可以忽略,从技术上说它们其实变化成了切片。
func modify(arr *[3]int) {  
    (*arr)[0] = 90
}

a[x] 是 (a)[x] 的简写形式,因此上面代码中的 (arr)[0] 可以替换为 arr[0]。

切片

使用make创建一个切片func make ([]type,len,cap) 声明切片的格式是: var slice []type(不需要说明长度)。 切片的初始化格式是:var slice1 []type = arr1[start:end] 切片自己不拥有任何数据,它只是底层数组的一种表示。切片在内部可由一个结构体表示.当切片传递给函数时,即使它通过值传递,指针变量也将引用相同的底层数组。

type slice struct {
Length int
Capacity int
ZerothElement *byte
}

内存优化,可以用copy(dst,src[]type)int 来生成一个切片副本,原来的给垃圾回收。 切片追加 func append(s[]type,x ... type) []type 追加后新切片是旧的两倍容量。 语法糖 可以用...的形式进一个可变参函数 如:append(sliceold,slice...)

可变参函数

可变参数函数的工作原理是把可变参数转换为一个新的切片。

Maps

make(map[type of key]type of value) 如:make(map[string]int) map 的零值是 nil。如果你想添加元素到 nil map 中,会触发运行时 panic。因此 map 必须使用 make 函数初始化。 也可以这样初始化 var a map[string]int = map[string]int{} 这样就不是nil了 value, ok := map[key] ok返回true代表由这个key map是引用类型

字符串

Go语言中的字符串是一个字节(byte)切片 byteSlice := []byte{0xe6,0xa0,0x88} 注意 这个切片,字符是"栈",占用了3个byte

结构体

声明结构体时也可以不用声明一个新类型,这样的结构体类型称为 匿名结构体(Anonymous Structure)。 编程中有时候需要一个临时的 struct 来封装数据,而这个 struct 的结构在其它地方又不会被二次复用,可以使用匿名 struct 来实现。(个人感觉是,相当于只能创造一个实例,不通用,因为没新类型,没兄弟啰~)

var user struct{Name string;age int}
user.Name = "name"
user.age = 18
var user = struct{Name string;Id int}{Name:"ok",Id:1}

又例如

chmap = make(chan struct{string;Entry}, 1000)
/*相当于
struct {
string//里面的;go系统自动加上
Entry
}
*/

结构体就是一个类,通常保存属性,方法相当于类的函数,不过有两种类型的接受者(对象),一种是值,一种是指针,指针能改变结构体中的属性值。 一个结构体( struct )就是一个字段的集合。 (而 type 的含义跟其字面意思相符。) 结构体字段使用点号来访问。

当结构体struct1是指针时 go允许我们用 struct1.字段 来代替显式的解引用 (*struct1).字段

初始化一个结构体实例的更简短和惯用的方式如下:

ms := &struct1{10, 15.5, "Chris"}
//表达式 new(Type) 和 &Type{} 是等价的。

或者:

var ms struct1
ms = struct1{10, 15.5, "Chris"}

方法

方法接收者 出现在 func 关键字和方法名之间的参数中。

func (方法接收者 newTypeOrStruct) 方法名(i int) string {
}

你可以对包中的 任意 类型定义任意方法,而不仅仅是针对结构体。 但是,不能对来自其他包的类型或基础类型定义方法。(意思是如果你要对int动手动脚,是不行的,需要另外type newint int)

方法可以与命名类型或命名类型的指针关联。方法也可以带参数

package main

import (
    "fmt"
)

type mystring string

func (self *mystring) change() {
    //如果传进去的不是指针,自动会转换为指针
    fmt.Printf("%v\n", self)
    *self = "NB"
}

func (self mystring) Copy() {
    //如果传进去的是指针,会自动copy一个指针指向的值
    fmt.Printf("%v\n", &self)
    self = "NC"
    fmt.Printf("%v\n", self)
}

func main() {
    var ok mystring = "SB"
    fmt.Printf("原始内存地址%v 值%v\n", &ok, ok)
    (&ok).Copy()
    fmt.Printf(值作为接收者 内存地址%v 值%v\n", &ok, ok)
    ok.change()
    fmt.Printf("指针作为接收者 内存地址%v 值%v\n", &ok, ok)
}

关于接口,这个文章比较有意思https://studygolang.com/articles/7123

golang 建立web服务器 http包源码详解

shownb commented 6 years ago

如果包名不是以 . 或 / 开头,如 "fmt" 或者 "container/list",则 Go 会在全局文件进行查找;如果包名以 ./ 开头,则 Go 会在相对目录中查找;如果包名以 / 开头(在 Windows 下也可以这样使用),则会在系统的绝对路径中查找。

类型

函数参数、返回值以及他们的类型统称为函数签名

尽量使用命名返回值:会使代码更清晰,更剪短,同时更加容易读懂

空白符 _

new和make

new 和 make 均是用于分配内存:new 用于值类型和用户定义的类型,如自定义结构,make 用于内置引用类型(切片、map 和管道)。它们的用法就像是函数,但是将类型作为参数:new(type)、make(type)。new(T) 分配类型 T 的零值并返回其地址,也就是指向类型 T 的指针(详见第 10.1 节)。它也可以被用于基本类型:v := new(int)。make(T) 返回类型 T 的初始化之后的值,因此它比 new 进行更多的工作(详见第 7.2.3/4 节、第 8.1.1 节和第 14.2.1 节)new() 是一个函数,不要忘记它的括号

函数的闭包 闭包是一个函数值,它引用了函数体之外的变量。 这个函数可以对这个引用的变量进行访问和赋值;换句话说这个函数被“绑定”在这个变量上。

func adder() func(int) int {
    sum := 0 //sum被锁住了
    return func(x int) int {
        sum += x
        return sum
    }
}
shownb commented 6 years ago
package main

import (
    "fmt"
)

type KfPig interface {
    GetPork() string
    GetSoup(giveWater int) int
    GetNoodle() int
}

type Pig struct {
    name []string
}

func (this *Pig) GetPork() string {
    fmt.Printf("%v won and be killed\n", this.name[0])
    return this.name[0]
}

func (this *Pig) GetSoup(giveWater int) int {
    fmt.Printf("many pigs are bathing..got 10L water\n")
    return 10
}

func (this *Pig) GetNoodle() int {
    fmt.Printf("many pigs are running..got 5kg Noodles\n")
    return 5
}

func Mix(x KfPig) {
    Pork := x.GetPork()
    Soup := x.GetSoup(20)
    Noodle := x.GetNoodle()
    fmt.Printf("%v + %v + %v = BestPorkRamen\n", Pork, Soup, Noodle)
}

func main() {
    pigs := Pig{name: []string{"p1", "p2", "p2"}}
    Mix(&pigs)
    fmt.Printf("done")
}

jhuvbfo

超级有用的解析接口的文章 https://studygolang.com/articles/12266

https://studygolang.com/articles/7123

https://porson.github.io/2017/02/05/Go语言关于Interface的理解与思考/

接口的作用就在于去作为"中间体"去调用结构体的成员方法

没有必要再去对接口内部的方法进行重新定义!!总之,使用接口可以非常灵活,而且与具体的实现做了解耦,如果以后有其他的实现类,只需要实现接口就可以了,而不用去改使用的时候的代码。

shownb commented 6 years ago

sanic vs go sanic with mysql(massive 10 pool)

# encoding: utf-8
from sanic import Sanic
from sanic.response import html

from model.tornadb import Conn
from config import Mysql_Setting

db = Conn()
app = Sanic()

@app.listener("before_server_start")
async def get_pool(app,loop):
    await db.create_poll(**Mysql_Setting)

@app.route("/")
async def test(request):
    many = await db.query("select id from t")
    return html(many)

if __name__ == '__main__':
    app.run(host="0.0.0.0",port=8080,access_log=False)

Concurrency Level: 10 Time taken for tests: 15.777 seconds Complete requests: 10000 Failed requests: 0 Total transferred: 1540000 bytes HTML transferred: 560000 bytes Requests per second: 633.83 [#/sec] (mean) Time per request: 15.777 [ms] (mean) Time per request: 1.578 [ms] (mean, across all concurrent requests) Transfer rate: 95.32 [Kbytes/sec] received

package main
import (
"fmt"
"io"
"net/http"
"database/sql"
_ "github.com/go-sql-driver/mysql"
)

var db *sql.DB
var err error

func init() {
    db, err = sql.Open("mysql", "root:toortoor@/typecho?charset=utf8")
    if err != nil {
        panic(err.Error())
    }
    db.SetMaxOpenConns(10)
    db.SetMaxIdleConns(10)
    db.Ping()
}

func test(w http.ResponseWriter, r *http.Request) {
    rows,_ := db.Query("select id from t")
    for rows.Next() {
        var id string
        if err := rows.Scan(&id); err != nil {
            panic(err.Error())
        }
        fmt.Printf("%s\n", id)
    }
    rows.Close()
    io.WriteString(w, "rows")
}

func main() {
    defer db.Close()
    fmt.Println("start")
    http.HandleFunc("/", test)
    http.ListenAndServe(":8080", nil)
}

Concurrency Level: 10 Time taken for tests: 10.768 seconds Complete requests: 10000 Failed requests: 0 Total transferred: 1200000 bytes HTML transferred: 40000 bytes Requests per second: 928.70 [#/sec] (mean) Time per request: 10.768 [ms] (mean) Time per request: 1.077 [ms] (mean, across all concurrent requests) Transfer rate: 108.83 [Kbytes/sec] received

shownb commented 6 years ago

多协程mysql https://studygolang.com/articles/7494 http://penghui.link/articles/2017/12/go_mysql.html

mysql 操作 golang学习之旅:使用go语言操作mysql数据库 golang连接mysql操作示例增删改查 MySQL唯一键重复的处理 []()

boltdb golang boltdb的学习和实践

package main
import (
"fmt"
"io"
"net/http"
"database/sql"
_ "github.com/go-sql-driver/mysql"
)

var db *sql.DB
var err error

func init() {
    db, err = sql.Open("mysql", "root:toortoor@tcp(127.0.0.1:3306)/typecho?charset=utf8")
    if err != nil {
        panic(err.Error())
    }
    db.SetMaxOpenConns(10)
    db.SetMaxIdleConns(10)
    //想验证是不是可以链接,清用ping来检查
    db.Ping()
}

func test(w http.ResponseWriter, r *http.Request) {
    ch := make(chan string)
    go func () {
        rows,_ := db.Query("select id from t")
        defer rows.Close()
        for rows.Next() {
            var id string
            if err := rows.Scan(&id); err != nil {
                panic(err.Error())
            }
            ch <- id
            //fmt.Printf("%s\n", id)
        }
        close(ch)
    }()
    for e := range ch{
        fmt.Printf("%s\n", e)
    }
    io.WriteString(w, "rows")
}

func main() {
    defer db.Close()
    fmt.Println("start")
    http.HandleFunc("/", test)
    http.ListenAndServe(":8080", nil)
}
shownb commented 6 years ago

Golang 微框架 Gin 简介 https://www.jianshu.com/p/a31e4ee25305 Gin实战:Gin+Mysql简单的Restful风格的API golang实践-如何实现高性能的定时任务管理器

框架写法参考 https://github.com/josephspurrier/gowebapp https://github.com/mlabouardy/movies-restapi

Form:存储了post、put和get参数,在使用之前需要调用ParseForm方法。 PostForm:存储了post、put参数,在使用之前需要调用ParseForm方法。 MultipartForm:存储了包含了文件上传的表单的post参数,在使用前需要调用ParseMultipartForm方法。

shownb commented 6 years ago

类似jinja2的模板继承 https://siongui.github.io/2017/02/05/go-template-inheritance-jinja2-extends-include/ 集合 Go 模板嵌套最佳实践

模板的语法

shownb commented 6 years ago

切片里面的坑。 如果将切片传进函数,但是如果再用append的话,可能返回的是新切片。 切片能够在函数能够引用传送,估计是建立在固定了长度之后。 如何避开 Go 中的各种陷阱 http://newton.sh/2016/11/07/如何避开-Go-中的各种陷阱/

shownb commented 6 years ago

Go 标准库剖析 1(transport http 请求的承载者)https://segmentfault.com/a/1190000003735562

如何实现支持数亿用户的长连消息系统 https://mp.weixin.qq.com/s?__biz=MzAwMDU1MTE1OQ==&mid=209727496&idx=1&sn=86b64ddadcc91bc6b0741a870692b3c0