golang web流量统计 上

tupunco 回复了问题 • 3 人关注 • 3 个回复 • 573 次浏览 • 2017-08-30 08:04 • 来自相关话题

go 1.9 多线程安全MAP 函数模块

alalmn 发表了文章 • 0 个评论 • 531 次浏览 • 2017-08-28 16:02 • 来自相关话题

package main

//go 1.9  多线程安全MAP  函数模块
//QQ:29295842  欢迎技术交流
import (
    //  "fmt"
    "s... 			查看全部
					
package main

//go 1.9 多线程安全MAP 函数模块
//QQ:29295842 欢迎技术交流
import (
// "fmt"
"sync"
)

var (
map_list sync.Map //广告配置信息
wgx sync.WaitGroup //
)

func Thread_map_add(id string, rows_map map[string]interface{}) { //添加数据
map_list.Store(id, rows_map)
}

func Thread_map_revise(id string, rows_map map[string]interface{}) { //修改
wgx.Add(1) //线程数
go func() {
map_list.LoadOrStore(id, rows_map) //修改
wgx.Done()
}()
wgx.Wait() //等待
}

func Thread_map_delete(id string) { //删除
wgx.Add(1) //线程数
go func() {
map_list.Delete(id) //删除
wgx.Done()
}()
wgx.Wait() //等待
}

func Thread_map_read(id string) (bool, string, map[string]interface{}) { //读取
read_bool := false
value := make(map[string]interface{})
value2, err := map_list.Load(id) //key读取
if err {
if valuexa, ok := value2.(map[string]interface{}); ok {
value = valuexa
read_bool = true
}
}
//fmt.Print("===%v==%v==\n", data, err)
//遍历读取
// map_list.Range(func(key, value2 interface{}) bool { //读取数据
// fmt.Println(key, "-----------", value2)
// // if valuexa, ok := value2.(map[string]interface{}); ok {
// // read_bool = true
// // //key = fmt.Sprintf("%v", key)
// // value = valuexa
// // }
// return true
// })
return read_bool, id, value
}

//fmt.Println("----------------")

// rows_map := make(map[string]interface{})
// rows_map["db_name"] = "098765"
// rows_map["list"] = "1234567"

// map_add("abc", rows_map)
// rows_map = make(map[string]interface{})
// rows_map["db_name"] = "aaaaaa"
// rows_map["list"] = "bbbbbbb"
// //map_add("123", rows_map)
// map_revise("abc", rows_map)
// rows_map3 := make(map[string]interface{})
// rows_map3["db_name"] = "rrrrr"
// rows_map3["list"] = "eeeeeee"
// map_add("1234", rows_map3)

// read_bool, key, re_map := map_read("abc")
// fmt.Printf("==%v==%v==%v==\n", read_bool, key, re_map["db_name"])

redis 分布式锁

toukii 发表了文章 • 0 个评论 • 316 次浏览 • 2017-08-26 12:48 • 来自相关话题

rddlock

github.com/everfore/rddlock

redis distribute lock

... 查看全部

rddlock


github.com/everfore/rddlock


redis distribute lock


redis 分布式锁, 实现原理:redis分布式锁


Usage


Lock & UnLock


lockkey := "lock-key"
timeout_ms := 3000

locked, ex := rddlock.Lock(rds, lockkey, timeout_ms)
defer reelock.UnLock(rds, lockkey, ex)

LockRetry


retry_times := 10
locked, ex := reelock.LockRetry(rds, lockkey, timeout_ms, retry_times) // get lock by retry
defer reelock.UnLock(rds, lockkey, ex)

UnLockUnsafe


直接删除key,可能会有问题:若删除之前,该key已经超时且被其他进程获得锁,将会删除其他进程的锁;删除之后,锁被释放,进而会有其他进程2获得锁。。。雪崩


locked, _ := rddlock.Lock(rds, lockkey, timeout_ms)
defer reelock.UnLockUnsafe(rds, lockkey)

SyncDo 异步执行任务


err := SyncDo(rds, lockkey, timeout_ms, func(timeout chan bool) chan bool {
ret := make(chan bool, 1)
go func() {
fmt.Println("doing...")
// TODO SOMETHING
select {
case <-timeout:
// do the rollback
break
case ret <- true:
fmt.Println("success end.")
}
}()
return ret
})

test


success:200, avg:1.1074123 ms
failed:0, avg:NaN ms
--- PASS: TestLockTime (10.59s)

#local-redis
=== RUN TestLockRetryTime
success:200, avg:1.1741205 ms
failed:0, avg:NaN ms
--- PASS: TestLockRetryTime (10.58s)

#uat-redis
=== RUN TestLockRetryTime
success:200, avg:12.572702 ms
failed:0, avg:NaN ms
--- PASS: TestLockRetryTime (10.59s)

欢迎指正 github.com/everfore/rddlock

PHP编码gzdeflate与Golang解码DEFLATE

qiangmzsx 发表了文章 • 0 个评论 • 175 次浏览 • 2017-08-25 00:00 • 来自相关话题

8月7日@黄同学找我问:“数据存到redis是gzdeflate压缩过的数据,golang从redis取出来,解压缩失败”。很多从PHP转Golang的业务经常会遇到,所以写下这篇博文,希望可以帮助更多人。
想要使用golang解码php的编... 查看全部

8月7日@黄同学找我问:“数据存到redis是gzdeflate压缩过的数据,golang从redis取出来,解压缩失败”。很多从PHP转Golang的业务经常会遇到,所以写下这篇博文,希望可以帮助更多人。

想要使用golang解码php的编码,那么就应该需要知道gzdeflate函数的算法是什么,先到gzdeflate文档,查看了一下发现:

gzdeflate使用的是纯粹的DEFLATE格式。这就与golang的compress/flate包一致了。有了了解就可以看着golang文档实现代码了。遂与@黄同学同学写了几个函数进行验证,最后定稿如下:


package main

import (
"strings"
"fmt"
"compress/flate"
"bytes"
"io/ioutil"
"github.com/bitly/go-simplejson"
)

func main() {

str:="test123"
b:=Gzdeflate(str,-1)
ss:=Gzdecode(string(b))
fmt.Println(ss)
}

// 解码
func Gzdecode(data string) string {
if data == "" {
return ""
}
r :=flate.NewReader(strings.NewReader(data))
defer r.Close()
out, err := ioutil.ReadAll(r)
if err !=nil {
fmt.Errorf("%s\n",err)
return ""
}
return string(out)
}

// 编码
func Gzdeflate(data string,level int) []byte {
if data == "" {
return []byte{}
}
var bufs bytes.Buffer
w,_ :=flate.NewWriter(&bufs,level)
w.Write([]byte(data))
w.Flush()
defer w.Close()
return bufs.Bytes()
}

// 编码
func GzdeflateForString(data string,level int) string {
if data == "" {
return ""
}
var bufs bytes.Buffer
w,_ :=flate.NewWriter(&bufs,level)
w.Write([]byte(data))
w.Flush()
defer w.Close()
return bufs.String()
}

经过@黄同学同学测试可以正确使用。留下wiki供后续遇到的同学查看。

快速搭建微服务--手把手教你服务发现与注册

wangxingge 发表了文章 • 2 个评论 • 545 次浏览 • 2017-08-24 19:23 • 来自相关话题

Build MicroService Platform --- Service Register and Discovery

Docker + Etcd + Registrator + App

现在的微服务很火,网络上... 查看全部

Build MicroService Platform --- Service Register and Discovery


Docker + Etcd + Registrator + App


现在的微服务很火,网络上各种文章也特别多,准备写一个快速搭建微服务的系列文章,读本文之前最好有点微服务的基础知识,这样比较好理解,以Golang为开发语言(因为这个目前比较火哈)

今天下午有时间就写第一部分,微服务的服务注册与发现,下次准备写Gate相关的分享。



  • 本文原创: 王星鸽,转发请加入原创建链接

  • 使用Centos7 的虚拟机, IP: 192.168.196.88

  • 在安装Docker 之前,还是先关闭防火墙吧,因为有很多的端口需要开

  • 搭建环境的时候要了解基本的使用docker命令。

  • 本文共分5部分

    • 安装 Docker

    • 安装 etcd

    • 安装 etcd-viewer

    • 安装 registrator

    • 测试



一、安装 Docker



  1. 从阿里云安装Docker: curl -sSL http://acs-public-mirror.oss-cn-hangzhou.aliyuncs.com/docker-engine/internet | sh -

  2. 设置镜像加速(在国内很多东西会被墙,建议使用镜像加速)

    1. 首先要有自己的阿里云账户(当然是免费的)

    2. 在阿里云中找到镜像仓库-> Docker Hub 镜像站点-> 您的专属加速地址

    3. 执行加速器配置脚本, 别忘了把地址换成 "您的专属加速地址"
      sudo mkdir -p /etc/docker
      sudo tee /etc/docker/daemon.json <<-'EOF'
      {
      "registry-mirrors": ["your-mirror-address"]
      }
      EOF
      sudo systemctl daemon-reload
      sudo systemctl restart docker



二、安装 Etcd



  1. 下载 etcd 地址: https://github.com/coreos/etcd/releases


  2. 搭建 etcd 的容器,因为要搭建的是etcd 集群,所以要创建多个etcd容器,我们用3个。



    1. 写 Dockerfile, 当然用官方的 Iamge 也可以。


    FROM centos:7

    COPY etcd /opt/etcd/etcd

    RUN chmod +x /opt/etcd/etcd

    EXPOSE 2379 2380

    CMD ["/opt/etcd/etcd"]


    1. Build Image: Docker build -rm -t etcd_image ./

    2. 启动容器,etcd启动参数详解


    # 启动容器1
    dk run --name ec_1 -p 12379:2379 -p 12380:2380 -d etcd_image \
    --name ec_node_1 \
    --listen-peer-urls http://0.0.0.0:2380 \
    --listen-client-urls http://0.0.0.0:2379 \
    --advertise-client-urls http://192.168.196.88:12379 \
    --initial-advertise-peer-urls http://192.168.196.88:12380 \
    --initial-cluster-token etcd-cluster-1 \
    --initial-cluster ec_node_1=http://192.168.196.88:12380,ec_node_2=http://192.168.196.88:22380,ec_node_3=http://192.168.196.88:32380 \
    --initial-cluster-state new

    # 启动容器2
    dk run --name ec_2 -p 22379:2379 -p 22380:2380 -d etcd_image \
    --name ec_node_2 \
    --listen-peer-urls http://0.0.0.0:2380 \
    --listen-client-urls http://0.0.0.0:2379 \
    --advertise-client-urls http://192.168.196.88:22379 \
    --initial-advertise-peer-urls http://192.168.196.88:22380 \
    --initial-cluster-token etcd-cluster-1 \
    --initial-cluster ec_node_1=http://192.168.196.88:12380,ec_node_2=http://192.168.196.88:22380,ec_node_3=http://192.168.196.88:32380 \
    --initial-cluster-state new

    # 启动容器3
    dk run --name ec_3 -p 32379:2379 -p 32380:2380 -d etcd_image \
    --name ec_node_3 \
    --listen-peer-urls http://0.0.0.0:2380 \
    --listen-client-urls http://0.0.0.0:2379 \
    --advertise-client-urls http://192.168.196.88:32379 \
    --initial-advertise-peer-urls http://192.168.196.88:32380 \
    --initial-cluster-token etcd-cluster-1 \
    --initial-cluster ec_node_1=http://192.168.196.88:12380,ec_node_2=http://192.168.196.88:22380,ec_node_3=http://192.168.196.88:32380 \
    --initial-cluster-state new


  3. 至此我们的 etcd集群搭建完成了。


三、安装 Etcd-viewer




  1. 搭建 etcd-viewer 的容器,直接从官方拉镜像:



    1. docker run -d -p 18080:8080 nikfoundas/etcd-viewer

    2. 访问etcd-viewer: http://192.168.196.88:18080



  2. 在etcd-viewer 中添加registry,成功之后如下图所示

    1. ec_1, http://192.168.196.88:12379

    2. ec_2, http://192.168.196.88:22379

    3. ec_3, http://192.168.196.88:32379



etcd-viewer


四、安装 Registrator



  1. 获取 Registrator镜像: docker pull gliderlabs/registrator

  2. 启动 Registrator容器,Registrator启动参数详解
    docker run -d --name=registrator --net=host --volume=/var/run/docker.sock:/tmp/docker.sock gliderlabs/registrator:latest etcd://192.168.196.88:12379

  3. 启动之后,就可以看见在当前宿主机启动着的所有容器,通过etcd-viewer就可以看到。

    etcd-viewer-registrator

  4. 至此 docker + etcd + etcd-viewer + registrator, 这个基于docker的服务注册的环境搭建完成了。


五、测试Service Registrator环境



  1. 写一个简单的Golang 的http服务,并编译生成可执行文件


package main

import (
"net/http"
"github.com/julienschmidt/httprouter"
"log"
)

func High(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
w.Write([]byte("done"))
}

var (
router = httprouter.New()
)

func main() {
router.GET("/test", High)
log.Fatal(http.ListenAndServe("0.0.0.0:80", router))
}


  1. 写 Dockerfile 来生成测试服务的镜像,写好就生成镜像: docker build --rm -t simple-http ./


FROM alpine:latest

RUN mkdir /lib64 && ln -s /lib/libc.musl-x86_64.so.1 /lib64/ld-linux-x86-64.so.2

COPY simpleService /opt/simpleService

RUN chmod +x /opt/simpleService

EXPOSE 80

CMD ["/opt/simpleService"]



  1. 创建并启动容器,我们测试的时候启动3个。



    1. docker run --name http_1 -d -P simple-http

    2. docker run --name http_2 -d -P simple-http

    3. docker run --name http_3 -d -P simple-http



  2. 创建完以后再查看容器是否都启动成功,docker ps -a

  3. 验证服务注册成功到etcd中,查看 etcd-viewer: http://192.168.196.88:18080

    etcd-test-service-1

    etcd-test-service-2

  4. 可以看到我们的服务都已经自动的写到了etcd集群中。再做两个测试:

    1. 动态添加容器,etcd中可以看到新服务。

    2. 动态添加容器,etcd中可以看到服务减少。

    3. 停止某个etcd容器,etcd集群还可以正常发现服务。



服务注册与发现环境搭建完成

Golang Label使用方法

haohongfan 发表了文章 • 0 个评论 • 292 次浏览 • 2017-08-22 10:00 • 来自相关话题

发现golang的label也是比较强大的, 这里看了一些资料, 搜集了一些特点, 欢迎指正 http://www.haoho...

阳历和阴历相互转化的工具类 golang版本

nosix 发表了文章 • 1 个评论 • 294 次浏览 • 2017-08-15 15:47 • 来自相关话题

github 地址 https://github.com/nosixtools/solarlunar

  1. 实现了阳历和阴历... 查看全部

github 地址 https://github.com/nosixtools/solarlunar



  1. 实现了阳历和阴历的相互转化,支持1900年到2049年。

  2. 支持节假日的计算


分享给你们


转化例子


package main 

import (
"github.com/nosixtools/solarlunar"
"fmt"
)

func main() {
solarDate := "1990-05-06"
fmt.Println(solarlunar.SolarToChineseLuanr(solarDate))
fmt.Println(solarlunar.SolarToSimpleLuanr(solarDate))

lunarDate := "1990-04-12"
fmt.Println(solarlunar.LunarToSolar(lunarDate, false))
}

节假日计算例子


package main

import (
"fmt"
"github.com/nosixtools/solarlunar/festival"
)

func main() {
festival := festival.NewFestival("./festival.json")
fmt.Println(festival.GetFestivals("2017-08-28"))
fmt.Println(festival.GetFestivals("2017-05-01"))
fmt.Println(festival.GetFestivals("2017-04-05"))
fmt.Println(festival.GetFestivals("2017-10-01"))
fmt.Println(festival.GetFestivals("2018-02-15"))
fmt.Println(festival.GetFestivals("2018-02-16"))
}

用Go实例学习Protobuf编码

ochapman 发表了文章 • 1 个评论 • 335 次浏览 • 2017-08-13 09:47 • 来自相关话题

Protobuf使用非常广泛,但是内部是怎么编码的呢,本文用Go的案例来学习protobuf编码规则。 https://slide.mua.io...

用喜欢和舒服的方式在Golang中使用锁、使用channel自定义锁

pathbox 发表了文章 • 4 个评论 • 450 次浏览 • 2017-08-12 18:52 • 来自相关话题

众所周知,我们能使用Golang轻松编写并发程序。Golang利用goroutine,让我们编写并发程序变得容易。并发程序中重要的问题之一就是如何正确的处理“竞争资源”或“共享资源”。Golang为我们提供了锁的机制。这篇文章,就简单介绍Golang中锁... 查看全部

众所周知,我们能使用Golang轻松编写并发程序。Golang利用goroutine,让我们编写并发程序变得容易。并发程序中重要的问题之一就是如何正确的处理“竞争资源”或“共享资源”。Golang为我们提供了锁的机制。这篇文章,就简单介绍Golang中锁的使用方法。并且进行错误的使用方法和正确的使用方法的代码示例对比。文章的所以代码示例在:https://github.com/pathbox/learning-go/tree/master/src/lock


原文链接


我们看第一个栗子:


package main

import (
"fmt"
"sync"
)

type Counter struct {
Value int
}

var wg sync.WaitGroup
var mutex sync.Mutex // 声明了一个全局锁
func main() {

wg.Add(1000)
counter := &Counter{Value: 0}

for i := 0; i < 1000; i++ {
go Count(counter, mutex)
}
wg.Wait()
fmt.Println("Count Value: ", counter.Value)
}

func Count(counter *Counter, mutex sync.Mutex) {
mutex.Lock()
defer mutex.Unlock()
counter.Value++
wg.Done()
}

/*
输出结果:
Count Value: 982
*/

这里声明了一个全局锁 sync.Mutex,然后将这个全局锁以参数的方式代入到方法中,这样并没有真正起到加锁的作用。


正确的方式是:


package main

import (
"fmt"
"sync"
)

type Counter struct {
Value int
}

var wg sync.WaitGroup
var mutex sync.Mutex // 声明了一个全局锁
func main() {

wg.Add(1000)
counter := &Counter{Value: 0}

for i := 0; i < 1000; i++ {
go Count(counter)
}
wg.Wait()
fmt.Println("Count Value: ", counter.Value)
}

func Count(counter *Counter) {
mutex.Lock()
defer mutex.Unlock()
counter.Value++
wg.Done()
}

/*
输出结果:
Count Value: 1000
*/

声明了一个全局锁后,其作用范围是全局。直接使用,而不是将其作为参数传递到方法中。


下一个栗子


package main

import (
"fmt"
"sync"
)

type Counter struct {
Value int
}

var wg sync.WaitGroup

func main() {
var mutex sync.Mutex // 声明了一个非全局锁
wg.Add(1000)
counter := &Counter{Value: 0}

for i := 0; i < 1000; i++ {
go Count(counter, mutex)
}
wg.Wait()
fmt.Println("Count Value: ", counter.Value)
}

func Count(counter *Counter, mutex sync.Mutex) {
mutex.Lock()
defer mutex.Unlock()
counter.Value++
wg.Done()
}

/*
输出结果:
Count Value: 954
*/

上面栗子中,声明的不是全局锁。然后将这个锁作为参数传入到Count()方法中,这样并没有真正起到加锁的作用。


正确的方式:


package main

import (
"fmt"
"sync"
)

type Counter struct {
Value int
}

var wg sync.WaitGroup

func main() {
mutex := &sync.Mutex{} // 定义了一个锁 mutex,赋值给mutex
wg.Add(1000)
counter := &Counter{Value: 0}

for i := 0; i < 1000; i++ {
go Count(counter, mutex)
}
wg.Wait()
fmt.Println("Count Value: ", counter.Value)
}

func Count(counter *Counter, mutex *sync.Mutex) {
mutex.Lock()
defer mutex.Unlock()
counter.Value++
wg.Done()
}

/*
输出结果:
Count Value: 1000
*/

这次通过 mutex := &sync.Mutex{},定义了mutex,然后作为参数传递到方法中,正确实现了加锁功能。


简单的说,在全局声明全局锁,之后这个全局锁就能在代码中的作用域范围内都能使用了。但是,也许你需要的不是全局锁。这和锁的粒度有关。
所以,你可以声明一个锁,在其作用域范围内使用,并且这个作用域范围是有并发执行的,别将锁当成参数传递。如果,需要将锁当成参数传递,那么你传的不是一个锁的声明,而是这个锁的指针。


下面,我们讨论一种更好的使用方式。通过阅读过很多”牛人“写的Go的程序或源码库,在锁的使用中。常常将锁放入对应的 struct 中定义,我觉得这是一种不错的方法。


package main

import (
"fmt"
"sync"
)

type Counter struct {
Value int
sync.Mutex
}

var wg sync.WaitGroup

func main() {

wg.Add(1000)
counter := &Counter{Value: 0}

for i := 0; i < 1000; i++ {
go Count(counter)
}
wg.Wait()
fmt.Println("Count Value: ", counter.Value)
}

func Count(counter *Counter) {
counter.Lock()
defer counter.Unlock()
counter.Value++
wg.Done()
}

/*
输出结果:
Count Value: 1000
*/

这样,我们声明的不是全局锁,并且这个需要加锁的竞争资源也正是 struct Counter 本身的Value属性,反映了这个锁的粒度。我觉得这是一种很舒服的使用方式(暂不知道这种方式会带来什么负面影响,如果有踩过坑的朋友,欢迎聊一聊这个坑),当然,如果你需要全局锁,那么请定义全局锁。


还可以有更多的使用方式:


// 1.
type Counter struct {
Value int
Mutex sync.Mutex
}

counter := &Counter{Value: 0}
counter.Mutex.Lock()
defer counter.Mutex.Unlock()

//2.
type Counter struct {
Value int
Mutex *sync.Mutex
}

counter := &Counter{Value: 0, Mutex: &sync.Mutex{}}
counter.Mutex.Lock()
defer counter.Mutex.Unlock()

Choose the way you like~


接下来,我们自己尝试创建一个互斥锁。


简单的说,简单的互斥锁锁的原理是:一个线程(进程)拿到了这个互斥锁,在这个时刻,只有这个线程(进程)能够进行互斥锁锁的范围中的"共享资源"的操作,主要是写操作。我们这里不讨论读锁的实现。锁的种类很多,有不同的实现场景和功能。这里我们讨论的是最简单的互斥锁。


我们能够利用Golang 的channel所具有特性,创建一个简单的互斥锁。


/locker/locker.go


package locker

// Mutext struct
type Mutex struct {
lock chan struct{}
}

// 创建一个互斥锁
func NewMutex() *Mutex {
return &Mutex{lock: make(chan struct{}, 1)}
}

// 锁操作
func (m *Mutex) Lock() {
m.lock <- struct{}{}
}

// 解锁操作
func (m *Mutex) Unlock() {
<-m.lock
}

main.go


package main

import (
"./locker"
"fmt"
"time"
)

type record struct {
lock *locker.Mutex
lock_count int
no_lock_count int
}

func newRecord() *record {
return &record{
lock: locker.NewMutex(),
lock_count: 0,
no_lock_count: 0,
}
}

func main() {
r := newRecord()

for i := 0; i < 1000; i++ {
go CountWithoutLock(r)
go CountWithLock(r)
}
time.Sleep(2 * time.Second)
fmt.Println("Record no_lock_count: ", r.no_lock_count)
fmt.Println("Record lock_count: ", r.lock_count)
}

func CountWithLock(r *record) {
r.lock.Lock()
defer r.lock.Unlock()
r.lock_count++
}

func CountWithoutLock(r *record) {
r.no_lock_count++
}

/* 输出结果
Record no_lock_count: 995
Record lock_count: 1000
*/

locker 就是通过使用channel的读操作和写操作会互相阻塞等待的这个同步性质。
可以简单的理解为,channel中传递的就是互斥锁。一个线程(进程)申请了一个互斥锁(struct{}{}),将这个互斥锁存放在channel中,
其他线程(进程)就没法申请互斥锁放入channel,而处于阻塞状态,等待channel恢复空闲空间。该线程(进程)进行操作”共享资源“,然后释放这个互斥锁(从channel中取走),channel这时候恢复了空闲的空间,其他线程(进程)
就能申请互斥锁并且放入channel。这样,在某一时刻,只会有一个线程(进程)拥有互斥锁,在操作"共享资源"。

官方依赖管理工具:dep

qiangmzsx 发表了文章 • 3 个评论 • 589 次浏览 • 2017-08-08 19:20 • 来自相关话题

在这里声明一下,百度或者google看到的godep不是我这篇博文说的dep,那它们是什么关系呢?按照查看全部

在这里声明一下,百度或者google看到的godep不是我这篇博文说的dep,那它们是什么关系呢?按照Peter Bourgon博文来说,它们的作者都有相同的人,但是一个是dep是官方版本,godep是第三方工具。

我今天介绍的是dep,之前也有介绍过glide,有兴趣的可以到Golang依赖管理工具:glide从入门到精通使用看看。
现在还有一个疑问是为什么官方现在要支持依赖管理了呢?我个人认为有如下原因(勿喷,如果不同或者遗漏欢迎留言补充):



  • 第三方依赖管理很多,虽然很好用,但是很少可以兼容的,结果--乱;

  • 官方的包管理为了增加社区的凝聚力,保持Go开箱即用的简单特性,不需要大家再安装各种第三方工具了,而且第三方工具都会过来兼容官方版的;

  • 还有一个官话,为了go更好的发展;

    dep的FAQ中有一段描述depgo get网址,也是侧面说了依赖管理工具和go get关系,
    一句话概括:依赖管理工具是为应用管理代码的,go get是为GOPATH管理代码的。


下面进入教程。


介绍


dep是一个原型依赖管理工具,需要在Go 1.7及更高的版本中使用,说明第三方工具近期还是有市场的。

PS:本博客的dep基于v0.3。


安装


环境准备。


//设置环境变量 使用vendor目录
GO15VENDOREXPERIMENT=1

安装dep


等到dep正式集成到Golang中时候,也许是Golang 1.10 ,广大吃瓜群众就可以直接使用go dep命令。现在还是需要自己安装的。


$ go get -u github.com/golang/dep/cmd/dep

验证安装


$ dep
dep is a tool for managing dependencies for Go projects

Usage: dep <command>

Commands:

init Initialize a new project with manifest and lock files
status Report the status of the project's dependencies
ensure Ensure a dependency is safely vendored in the project
prune Prune the vendor tree of unused packages

Examples:
dep init set up a new project
dep ensure install the project's dependencies
dep ensure -update update the locked versions of all dependencies
dep ensure -add github.com/pkg/errors add a dependency to the project

Use "dep help [command]" for more information about a command.

有一个很重要的选项ensure中文含义是确保;保证;担保,作者想传达的意思是确保所有本地状态-代码树、清单、锁和供应商彼此同步


看到这个说明已经安装好了。


使用


老规矩,篇幅有限,我只介绍经常使用到的。
先进入在GOPATH的一个项目中。


cd $GOPATH/src/foordep

初始化(dep init)


$ cd foordep/
$ dep init
$ ll
total 12
-rw-rw-r-- 1 qiangmzsx qiangmzsx 286 Aug 7 11:45 Gopkg.lock
-rw-rw-r-- 1 qiangmzsx qiangmzsx 535 Aug 7 11:45 Gopkg.toml
drwxrwxr-x 2 qiangmzsx qiangmzsx 4096 Aug 7 11:45 vendor

大家发现了,应用foordep目录下出现了两个文件(Gopkg.lock、Gopkg.toml)和一个目录(vendor)。
它们是什么关系呢?

关系

所以出现Gopkg.toml and Gopkg.lock are out of sync.时候最好执行一下dep ensure


下面看看它们的内容。


$ cat Gopkg.lock 
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.

[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "ab4fef131ee828e96ba67d31a7d690bd5f2f42040c6766b1b12fe856f87e0ff7"
solver-name = "gps-cdcl"
solver-version = 1
$ cat Gopkg.toml

# Gopkg.toml example
#
# Refer to https://github.com/golang/dep/ ... ml.md
# for detailed Gopkg.toml documentation.
#
# required = ["github.com/user/thing/cmd/thing"]
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
#
# [[constraint]]
# name = "github.com/user/project"
# version = "1.0.0"
#
# [[constraint]]
# name = "github.com/user/project2"
# branch = "dev"
# source = "github.com/myfork/project2"
#
# [[override]]
# name = "github.com/x/y"
# version = "2.4.0"

dep ensure


我们写一个Gopkg.toml看看效果。


# 必需包
required = ["github.com/astaxie/beego"]
# 忽略包
ignored = ["golang.org/x/crypto"]
# 项目元数据
[metadata]
homepage = "https://github.com/qiangmzsx"
license = "MIT"
owners_name_1 = "qiangmzsx"
owners_email_1 = "qiangmzsx@hotmail.com"
owners_homepage_1 = "https://github.com/qiangmzsx"

# 约束条件
[[constraint]]
name = "github.com/astaxie/beego"
# 可选:版本
version = "=1.8.0"
# 分支
#branch = "master"
# 修订
#revision = "beego 1.8.0"
# 可选:指定来源
source = "github.com/astaxie/beego"

但是怎么样执行?可以执行如下命令寻找帮助:


$ dep help ensure
Usage: dep ensure [-update | -add] [-no-vendor | -vendor-only] [-dry-run] [<spec>...]

Project spec:

<import path>[:alt source URL][@<constraint>]

Ensure gets a project into a complete, reproducible, and likely compilable state:

* All non-stdlib imports are fulfilled
* All rules in Gopkg.toml are respected
* Gopkg.lock records precise versions for all dependencies
* vendor/ is populated according to Gopkg.lock

Ensure has fast techniques to determine that some of these steps may be
unnecessary. If that determination is made, ensure may skip some steps. Flags
may be passed to bypass these checks; -vendor-only will allow an out-of-date
Gopkg.lock to populate vendor/, and -no-vendor will update Gopkg.lock (if
needed), but never touch vendor/.

The effect of passing project spec arguments varies slightly depending on the
combination of flags that are passed.

Examples:

dep ensure Populate vendor from existing Gopkg.toml and Gopkg.lock
dep ensure -add github.com/pkg/foo Introduce a named dependency at its newest version
dep ensure -add github.com/pkg/foo@^1.0.1 Introduce a named dependency with a particular constraint

For more detailed usage examples, see dep ensure -examples.

Flags:

-add add new dependencies, or populate Gopkg.toml with constraints for existing dependencies (default: false)
-dry-run only report the changes that would be made (default: false)
-examples print detailed usage examples (default: false)
-no-vendor update Gopkg.lock (if needed), but do not update vendor/ (default: false)
-update update the named dependencies (or all, if none are named) in Gopkg.lock to the latest allowed by Gopkg.toml (default: false)
-v enable verbose logging (default: false)
-vendor-only populate vendor/ from Gopkg.lock without updating it first (default: false)

执行一下


$ dep ensure
all dirs lacked any go code

错误了,这是因为foordep目录下没有任何的go代码,只能加上一个看看。


$ vim main.go
package main

import (
"github.com/astaxie/beego"
"runtime"
)

func main() {
maxCPU := runtime.NumCPU()
runtime.GOMAXPROCS(maxCPU)
beego.Run()
}

再来试试看。


$ dep ensure
$ ll vendor/
total 4
drwxrwxr-x 3 qiangmzsx qiangmzsx 4096 Aug 7 16:29 github.com

看看Gopkg.lock的内容。


# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.

[[projects]]
name = "github.com/astaxie/beego"
packages = [".","config","context","grace","logs","session","toolbox","utils"]
revision = "323a1c4214101331a4b71922c23d19b7409ac71f"
source = "github.com/astaxie/beego"
version = "v1.8.0"

[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "6fb93334da1b165aaab11f170d871a92b40033575e66e2cf4289e77e0d64551d"
solver-name = "gps-cdcl"
solver-version = 1

现在需要解析json,我们试试使用命令行的方式导入github.com/bitly/go-simplejson包。


$ dep ensure -add github.com/bitly/go-simplejson
$ Gopkg.lock
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.

[[projects]]
name = "github.com/astaxie/beego"
packages = [".","config","context","grace","logs","session","toolbox","utils"]
revision = "323a1c4214101331a4b71922c23d19b7409ac71f"
source = "github.com/astaxie/beego"
version = "v1.8.0"

[[projects]]
name = "github.com/bitly/go-simplejson"
packages = ["."]
revision = "aabad6e819789e569bd6aabf444c935aa9ba1e44"
version = "v0.5.0"

[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "6fb93334da1b165aaab11f170d871a92b40033575e66e2cf4289e77e0d64551d"
solver-name = "gps-cdcl"
solver-version = 1

可以发现多了github.com/bitly/go-simplejson,但是Gopkg.toml并没有任何改变。
注意:执行dep ensure -add时候报错


$ dep ensure -add github.com/bitly/go-simplejson
Gopkg.toml and Gopkg.lock are out of sync. Run a plain dep ensure to resync them before attempting to -add

还可以指定依赖的版本:


$ dep ensure -add github.com/bitly/go-simplejson@=0.4.3

是因为Gopkg.tomlGopkg.lock不同步了,需要重新执行一下dep ensure即可。
重新整理一下Gopkg.toml


# 必需包
required = ["github.com/astaxie/beego"]
# 忽略包
ignored = ["golang.org/x/crypto"]
# 项目元数据
[metadata]
homepage = "https://github.com/qiangmzsx"
license = "MIT"
owners_name_1 = "qiangmzsx"
owners_email_1 = "qiangmzsx@hotmail.com"
owners_homepage_1 = "https://github.com/qiangmzsx"

# 约束条件
[[constraint]]
name = "github.com/astaxie/beego"
# 可选:版本
version = "=1.8.0"
# 分支
#branch = "master"
# 修订
#revision = "beego 1.8.0"
# 可选:指定来源
source = "github.com/astaxie/beego"

[[constraint]]
name = "github.com/bitly/go-simplejson"
branch = "master"
source = "https://github.com/bitly/go-simplejson.git"

Gopkg.tomlversion规则:
~=version使用的操作符规则,如果仅仅是指定version = "1.8.0",那么dep会自动加上^,表示最左边的非零位的版本加一


^1.2.3 意味 1.2.3 <= X < 2.0.0
^0.2.3 意味 0.2.3 <= X < 0.3.0
^0.0.3 意味 0.0.3 <= X < 0.1.0

如果执行dep ensure时候出现


$ dep  ensure 
error while parsing /home/users/qiangmzsx/golang/src/foordep/Gopkg.toml: multiple constraints specified for github.com/astaxie/beego, can only specify one

说明配置写错了,需要看看Gopkg.toml文件中是不是同时配置了versionbranchrevision


空配置


我们现在尝试着把foordep目录情况就留下main.go


package main

import (
"github.com/astaxie/beego"
"github.com/bitly/go-simplejson"
"runtime"
)

func main() {
maxCPU := runtime.NumCPU()
runtime.GOMAXPROCS(maxCPU)
strJson := `{"announcer": {"nickname": "非议讲史", "kind": "user", "created_at": 1494904539000, "updated_at": 1494983507000, "track_id": 38088960}}`
mapJson,_:=simplejson.NewJson([]byte(strJson))
println(mapJson)
beego.Run()
}

执行dep ensure 为了更好地看到过程,加上参数-v


$ dep init -v
Root project is "foordep"
1 transitively valid internal packages
2 external packages imported from 2 projects
(0) ✓ select (root)
(1) ? attempt github.com/bitly/go-simplejson with 1 pkgs; 5 versions to try
(1) try github.com/bitly/go-simplejson@v0.5.0
(1) ✓ select github.com/bitly/go-simplejson@v0.5.0 w/1 pkgs
(2) ? attempt github.com/astaxie/beego with 1 pkgs; 23 versions to try
(2) try github.com/astaxie/beego@v1.8.3
(2) ✓ select github.com/astaxie/beego@v1.8.3 w/9 pkgs
✓ found solution with 10 packages from 2 projects

Solver wall times by segment:
b-list-versions: 3.926086724s
b-list-pkgs: 285.209471ms
b-gmal: 266.828805ms
select-atom: 3.417834ms
satisfy: 3.126864ms
select-root: 428.276µs
new-atom: 234.106µs
other: 45.014µs
b-source-exists: 6.946µs
b-deduce-proj-root: 3.472µs

TOTAL: 4.485387512s

Using ^0.5.0 as constraint for direct dep github.com/bitly/go-simplejson
Locking in v0.5.0 (aabad6e) for direct dep github.com/bitly/go-simplejson
Using ^1.8.3 as constraint for direct dep github.com/astaxie/beego
Locking in v1.8.3 (cab8458) for direct dep github.com/astaxie/beego

此时再查看Gopkg.tomlGopkg.lock文件:


$ vim Gopkg.toml
[[constraint]]
name = "github.com/astaxie/beego"
version = "1.8.3"

[[constraint]]
name = "github.com/bitly/go-simplejson"
version = "0.5.0"

$ vim Gopkg.lock
[[projects]]
name = "github.com/astaxie/beego"
packages = [".","config","context","context/param","grace","logs","session","toolbox","utils"]
revision = "cab8458c1c4a5a3b4bf5192922be620e6dede15b"
version = "v1.8.3"

[[projects]]
name = "github.com/bitly/go-simplejson"
packages = ["."]
revision = "aabad6e819789e569bd6aabf444c935aa9ba1e44"
version = "v0.5.0"

[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "dc040fb12390d61768be6388ad2935bdd7f9cc93d4b1fdda421a284058277c80"
solver-name = "gps-cdcl"
solver-version = 1

glide一样,具有自举功能,不知道这个名词用得对不对。dep会自动根据代码生成Gopkg.tomlGopkg.lock配置文件。

PS:但是不建议使用,因为其拉取的依赖包都是最新的,可能出现不兼容,再者我国是一个被墙的地方。


dep cache


看到这里时候很多人都会有疑问?dep的依赖包每一次都是拉取新的还是优先使用本地cache呢?可以肯定的是
dep也是有本地缓存的,大家可以打开$GOPATH/pkg/dep/看看,是不是存在呢!

下面我们做两个测试看看。


$GOPATH/src不存在依赖包


环境准备,将原来的cache和vendor清空,别遗漏了$GOPATH/src中的github.com/bitly/go-simplejson


$ ll
total 4
-rwxr--r-- 1 qiangmzsx qiangmzsx 990 Aug 7 16:39 main.go
$ vim main.go
package main

import (
"github.com/astaxie/beego"
"github.com/bitly/go-simplejson"
"runtime"
)

func main() {
maxCPU := runtime.NumCPU()
runtime.GOMAXPROCS(maxCPU)
strJson := `{"announcer": {"nickname": "非议讲史", "kind": "user", "updated_at": 1494983507000, "track_id": 38088960}}`
mapJson,_:=simplejson.NewJson([]byte(strJson))
println(mapJson)
beego.Run()
}

执行dep init -gopath -v查看初始化过程。


$ ll
total 4
-rwxr--r-- 1 qiangmzsx qiangmzsx 382 Aug 8 12:47 main.go
$ dep init -gopath -v
Searching GOPATH for projects...
Following dependencies were not found in GOPATH. Dep will use the most recent versions of these projects.
github.com/bitly/go-simplejson
Root project is "foordep"
1 transitively valid internal packages
2 external packages imported from 2 projects
(0) ✓ select (root)
(1) ? attempt github.com/astaxie/beego with 1 pkgs; at least 1 versions to try
(1) try github.com/astaxie/beego@76ce912a30f9255d8d353d365ab99cb069fd29e0
(1) ✗ Unable to update checked out version: fatal: reference is not a tree: 76ce912a30f9255d8d353d365ab99cb069fd29e0
(1) try github.com/astaxie/beego@v1.8.3
(1) ✓ select github.com/astaxie/beego@v1.8.3 w/9 pkgs
(2) ? attempt github.com/bitly/go-simplejson with 1 pkgs; 5 versions to try
(2) try github.com/bitly/go-simplejson@v0.5.0
(2) ✓ select github.com/bitly/go-simplejson@v0.5.0 w/1 pkgs
✓ found solution with 10 packages from 2 projects

Solver wall times by segment:
b-list-pkgs: 320.955115ms
b-gmal: 274.950203ms
satisfy: 8.179966ms
select-atom: 2.62224ms
new-atom: 392.168µs
b-list-versions: 254.937µs
select-root: 209.152µs
b-deduce-proj-root: 40.45µs
other: 37.01µs
b-source-exists: 5.83µs

TOTAL: 607.647071ms

Using ^1.8.3 as constraint for direct dep github.com/astaxie/beego
Locking in v1.8.3 (cab8458) for direct dep github.com/astaxie/beego
Using ^0.5.0 as constraint for direct dep github.com/bitly/go-simplejson
Locking in v0.5.0 (aabad6e) for direct dep github.com/bitly/go-simplejson

日志显示,dep首先从$GOPATH查找github.com/bitly/go-simplejson,因为没有找到才从网络下载。


$GOPATH存在依赖包


环境准备,将原来的cache和vendor清空,注意$GOPATH/src中的github.com/bitly/go-simplejson存在。


$ ll
total 4
-rwxr--r-- 1 qiangmzsx qiangmzsx 382 Aug 8 12:47 main.go
$ dep init -gopath -v
Searching GOPATH for projects...
Using master as constraint for direct dep github.com/bitly/go-simplejson
Locking in master (da1a892) for direct dep github.com/bitly/go-simplejson
Root project is "foordep"
1 transitively valid internal packages
2 external packages imported from 2 projects
(0) ✓ select (root)
(1) ? attempt github.com/astaxie/beego with 1 pkgs; at least 1 versions to try
(1) try github.com/astaxie/beego@76ce912a30f9255d8d353d365ab99cb069fd29e0
(1) ✗ Unable to update checked out version: fatal: reference is not a tree: 76ce912a30f9255d8d353d365ab99cb069fd29e0
(1) try github.com/astaxie/beego@v1.8.3
(1) ✓ select github.com/astaxie/beego@v1.8.3 w/9 pkgs
(2) ? attempt github.com/bitly/go-simplejson with 1 pkgs; at least 1 versions to try
(2) try github.com/bitly/go-simplejson@master
(2) ✓ select github.com/bitly/go-simplejson@master w/1 pkgs
✓ found solution with 10 packages from 2 projects

Solver wall times by segment:
b-list-pkgs: 312.646734ms
b-gmal: 265.066047ms
satisfy: 6.488056ms
select-atom: 3.287416ms
new-atom: 397.837µs
select-root: 373.267µs
b-list-versions: 108.466µs
other: 47.43µs
b-source-exists: 7.71µs
b-deduce-proj-root: 6.568µs

TOTAL: 588.429531ms

Using ^1.8.3 as constraint for direct dep github.com/astaxie/beego
Locking in v1.8.3 (cab8458) for direct dep github.com/astaxie/beego

可以看到github.com/bitly/go-simplejson是优先从$GOPATH获取的。 好处我个人认为有两个:



  • 节省时间;

  • 本地类库的稳定性和兼容性已经经过用户验证了。


dep v0.1时候还不需要手动加上-gopath选项,dep工具会自动判断,但是dep v0.3后如果没有加上-gopath那么默认就是从网络下载。


更新配置 (dep ensure -update)


现在修改foordep项目的Gopkg.toml内容为:


$ vim  Gopkg.toml
[[constraint]]
name = "github.com/astaxie/beego"
# 约束为1.8.0
version = "=1.8.0"

[[constraint]]
name = "github.com/bitly/go-simplejson"
version = "0.5.0"
$ dep ensure -update
Gopkg.toml and Gopkg.lock are out of sync. Run a plain dep ensure to resync them before attempting to -update
$ dep ensure
$ dep ensure -update -v
Root project is "foordep"
1 transitively valid internal packages
2 external packages imported from 2 projects
(0) ✓ select (root)
(1) ? attempt github.com/astaxie/beego with 1 pkgs; 23 versions to try
(1) try github.com/astaxie/beego@v1.8.3
(2) ✗ github.com/astaxie/beego@v1.8.3 not allowed by constraint 1.8.0:
(2) 1.8.0 from (root)
(1) try github.com/astaxie/beego@v1.8.2
(2) ✗ github.com/astaxie/beego@v1.8.2 not allowed by constraint 1.8.0:
(2) 1.8.0 from (root)
(1) try github.com/astaxie/beego@v1.8.1
(2) ✗ github.com/astaxie/beego@v1.8.1 not allowed by constraint 1.8.0:
(2) 1.8.0 from (root)
(1) try github.com/astaxie/beego@v1.8.0
(1) ✓ select github.com/astaxie/beego@v1.8.0 w/8 pkgs
(2) ? attempt github.com/bitly/go-simplejson with 1 pkgs; 5 versions to try
(2) try github.com/bitly/go-simplejson@v0.5.0
(2) ✓ select github.com/bitly/go-simplejson@v0.5.0 w/1 pkgs
✓ found solution with 9 packages from 2 projects

Solver wall times by segment:
b-source-exists: 4.00794324s
b-list-pkgs: 2.545452669s
b-gmal: 276.070372ms
satisfy: 5.179016ms
select-atom: 4.337704ms
new-atom: 1.359055ms
b-list-versions: 467.799µs
b-matches: 371.239µs
select-root: 193.471µs
b-pair-rev: 127.992µs
other: 25.962µs
b-pair-version: 7.866µs

TOTAL: 6.841536385s

$ dep status
PROJECT CONSTRAINT VERSION REVISION LATEST PKGS USED
github.com/astaxie/beego 1.8.0 v1.8.0 323a1c4 323a1c4 8
github.com/bitly/go-simplejson ^0.5.0 v0.5.0 aabad6e aabad6e 1

后记


看到了这里,那么对dep已经可以进行基本的使用了,不过目前而言,dep还不够稳定,谁也不知道后续会怎么样更改,尝鲜可以,个人还不建议使用在线上。
如果大家喜欢这篇博文请点赞或者留言,有不同见解的也请留言讨论。

Golang高性能json包:easyjson

qiangmzsx 发表了文章 • 7 个评论 • 690 次浏览 • 2017-08-04 21:01 • 来自相关话题

简介

easyjson是什么呢? 根据官网介绍,easyjson是提供高效快速且易用的结构体structs<-->json转换... 查看全部

简介


easyjson是什么呢?
根据官网介绍,easyjson是提供高效快速且易用的结构体structs<-->json转换包。easyjson并没有使用反射方式实现,所以性能比其他的json包该4-5倍,比golang 自带的json包快2-3倍。
easyjson目标是维持生成去代码简单,以致于它可以轻松地进行优化或固定。


安装



go get -u github.com/mailru/easyjson/
go install github.com/mailru/easyjson/easyjson
or
go build -o easyjson github.com/mailru/easyjson/easyjson

验证是否安装成功。


$ easyjson
Usage of D:\Code\go\bin\easyjson.exe:
-all
generate marshaler/unmarshalers for all structs in a file
-build_tags string
build tags to add to generated file
-leave_temps
do not delete temporary files
-lower_camel_case
use lowerCamelCase names instead of CamelCase by default
-no_std_marshalers
don't generate MarshalJSON/UnmarshalJSON funcs
-noformat
do not run 'gofmt -w' on output file
-omit_empty
omit empty fields by default

string
specify the filename of the output
-pkg
process the whole package instead of just the given file
-snake_case
use snake_case names instead of CamelCase by default
-stubs
only generate stubs for marshaler/unmarshaler funcs

其中有几个选项需要注意:


-lower_camel_case:将结构体字段field首字母改为小写。如Name=>name。  
-build_tags string:将指定的string生成到生成的go文件头部。
-no_std_marshalers:不为结构体生成MarshalJSON/UnmarshalJSON函数。
-omit_empty:没有赋值的field可以不生成到json,否则field为该字段类型的默认值。
-output_filename:定义生成的文件名称。
-pkg:对包内指定有`//easyjson:json`结构体生成对应的easyjson配置。
-snke_case:可以下划线的field如`Name_Student`改为`name_student`。

使用


记得在需要使用easyjson的结构体上加上//easyjson:json
如下:


//easyjson:json
type School struct {
Name string `json:"name"`
Addr string `json:"addr"`
}

//easyjson:json
type Student struct {
Id int `json:"id"`
Name string `json:"s_name"`
School School `json:"s_chool"`
Birthday time.Time `json:"birthday"`
}

在结构体包下执行


easyjson  -all student.go

此时在该目录下出现一个新的文件。


// Code generated by easyjson for marshaling/unmarshaling. DO NOT EDIT.

package easyjson

import (
json "encoding/json"
easyjson "github.com/mailru/easyjson"
jlexer "github.com/mailru/easyjson/jlexer"
jwriter "github.com/mailru/easyjson/jwriter"
)

// suppress unused package warning
var (
_ *json.RawMessage
_ *jlexer.Lexer
_ *jwriter.Writer
_ easyjson.Marshaler
)

func easyjsonB83d7b77DecodeStudygoEasyjson(in *jlexer.Lexer, out *Student) {
isTopLevel := in.IsStart()
if in.IsNull() {
if isTopLevel {
in.Consumed()
}
in.Skip()
return
}
in.Delim('{')
for !in.IsDelim('}') {
key := in.UnsafeString()
in.WantColon()
if in.IsNull() {
in.Skip()
in.WantComma()
continue
}
switch key {
case "id":
out.Id = int(in.Int())
case "s_name":
out.Name = string(in.String())
case "s_chool":
easyjsonB83d7b77DecodeStudygoEasyjson1(in, &out.School)
case "birthday":
if data := in.Raw(); in.Ok() {
in.AddError((out.Birthday).UnmarshalJSON(data))
}
default:
in.SkipRecursive()
}
in.WantComma()
}
in.Delim('}')
if isTopLevel {
in.Consumed()
}
}
func easyjsonB83d7b77EncodeStudygoEasyjson(out *jwriter.Writer, in Student) {
out.RawByte('{')
first := true
_ = first
if !first {
out.RawByte(',')
}
first = false
out.RawString("\"id\":")
out.Int(int(in.Id))
if !first {
out.RawByte(',')
}
first = false
out.RawString("\"s_name\":")
out.String(string(in.Name))
if !first {
out.RawByte(',')
}
first = false
out.RawString("\"s_chool\":")
easyjsonB83d7b77EncodeStudygoEasyjson1(out, in.School)
if !first {
out.RawByte(',')
}
first = false
out.RawString("\"birthday\":")
out.Raw((in.Birthday).MarshalJSON())
out.RawByte('}')
}

// MarshalJSON supports json.Marshaler interface
func (v Student) MarshalJSON() ([]byte, error) {
w := jwriter.Writer{}
easyjsonB83d7b77EncodeStudygoEasyjson(&w, v)
return w.Buffer.BuildBytes(), w.Error
}

// MarshalEasyJSON supports easyjson.Marshaler interface
func (v Student) MarshalEasyJSON(w *jwriter.Writer) {
easyjsonB83d7b77EncodeStudygoEasyjson(w, v)
}

// UnmarshalJSON supports json.Unmarshaler interface
func (v *Student) UnmarshalJSON(data []byte) error {
r := jlexer.Lexer{Data: data}
easyjsonB83d7b77DecodeStudygoEasyjson(&r, v)
return r.Error()
}

// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
func (v *Student) UnmarshalEasyJSON(l *jlexer.Lexer) {
easyjsonB83d7b77DecodeStudygoEasyjson(l, v)
}
func easyjsonB83d7b77DecodeStudygoEasyjson1(in *jlexer.Lexer, out *School) {
isTopLevel := in.IsStart()
if in.IsNull() {
if isTopLevel {
in.Consumed()
}
in.Skip()
return
}
in.Delim('{')
for !in.IsDelim('}') {
key := in.UnsafeString()
in.WantColon()
if in.IsNull() {
in.Skip()
in.WantComma()
continue
}
switch key {
case "name":
out.Name = string(in.String())
case "addr":
out.Addr = string(in.String())
default:
in.SkipRecursive()
}
in.WantComma()
}
in.Delim('}')
if isTopLevel {
in.Consumed()
}
}
func easyjsonB83d7b77EncodeStudygoEasyjson1(out *jwriter.Writer, in School) {
out.RawByte('{')
first := true
_ = first
if !first {
out.RawByte(',')
}
first = false
out.RawString("\"name\":")
out.String(string(in.Name))
if !first {
out.RawByte(',')
}
first = false
out.RawString("\"addr\":")
out.String(string(in.Addr))
out.RawByte('}')
}

现在可以写一个测试类啦。



package main

import (
"studygo/easyjson"
"time"
"fmt"
)

func main(){
s:=easyjson.Student{
Id: 11,
Name:"qq",
School:easyjson.School{
Name:"CUMT",
Addr:"xz",
},
Birthday:time.Now(),
}
bt,err:=s.MarshalJSON()
fmt.Println(string(bt),err)
json:=`{"id":11,"s_name":"qq","s_chool":{"name":"CUMT","addr":"xz"},"birthday":"2017-08-04T20:58:07.9894603+08:00"}`
ss:=easyjson.Student{}
ss.UnmarshalJSON([]byte(json))
fmt.Println(ss)
}

运行结果:


{"id":11,"s_name":"qq","s_chool":{"name":"CUMT","addr":"xz"},"birthday":"2017-08-04T20:58:07.9894603+08:00"} <nil>
{121 {CwwwwwwwUMT xzwwwww} 2017-08-04 20:52:03.4066002 +0800 CST}

[译]go styleguide

回复

Xargin 发起了问题 • 1 人关注 • 0 个回复 • 500 次浏览 • 2017-08-04 17:39 • 来自相关话题

golang面向对象分析

jeson 回复了问题 • 4 人关注 • 2 个回复 • 598 次浏览 • 2017-08-04 10:21 • 来自相关话题

Glide--Golang包版本管理工具

Julyqi 发表了文章 • 3 个评论 • 333 次浏览 • 2017-08-03 15:42 • 来自相关话题

Golang挺好用的,但是目前比较受到诟病的是其没有自带包管理工具(golang社区已经发起了一个dep的项目,不过要正式被golang接受还需要一段时间)。官方没有咋办,那就自己造轮子呗。所以 go的包管理工具就五花八门、层出不穷了。目前有Glide,... 查看全部

Golang挺好用的,但是目前比较受到诟病的是其没有自带包管理工具(golang社区已经发起了一个dep的项目,不过要正式被golang接受还需要一段时间)。官方没有咋办,那就自己造轮子呗。所以 go的包管理工具就五花八门、层出不穷了。目前有Glide, gopm, godep,gpm,gom等等。。。


这里介绍一个工具,使用比较简单: glide


说明原因:因为我也是分享给大家的,原文内容如果更新了,这个还是原来的内容不同步呢,而且大家如果真的感兴趣,点击查看也不会大家几分钟的。


下载说明

应届生求职

cloverstd 回复了问题 • 1 人关注 • 1 个回复 • 492 次浏览 • 2017-08-03 13:34 • 来自相关话题