sublime text3解决Gosublime无法自动补全代码

版本

  1. Sublime Text3.2.1
  2. go version go1.12.1 darwin/amd64
  3. Gosublime 18.11.28

安装Gosublime

打开Perferences–Browse Packages…,进入Gosublime,在命令行里输入:

阅读全文   2019/7/8 文章分类: 操作系统相关

Javascript对象与JSON的互转

var obj = JSON.parse(json); //由JSON字符串转换为JSON对象

var json=JSON.stringify(obj); //将JSON对象转化为JSON字符

//此种需下载插件
var json=obj.toJSONString(); //将JSON对象转化为JSON字符

2019/5/6 文章分类: GO语言技巧

golang 1.12 版本的自动补全问题

问题

golang 1.12 开始, 默认的 go install 不再生成 pkg 文件.
所以对第三方库的引用, 无法进行代码的自动补全.

解决方法

go install -i 会生成 pkg 文件夹和编译文件

2019/5/6 文章分类: GO语言技巧

Golang结构体遍历

package main

import (
        "fmt"
        "reflect"
)

type User struct  {
        Id int
        Name string
        //addr string
}

func main(){
        u := User{Id:1001, Name:"xxx"/*, addr:"xxx"*/}
        t := reflect.TypeOf(u)
        v := reflect.ValueOf(u)
        for k := 0; k < t.NumField(); k++ {
                fmt.Printf("%s -- %v \n", t.Field(k).Name, v.Field(k).Interface())   
        }
}

2019/5/3 文章分类: GO语言技巧

golang通过反射获取和设置结构体字段的值

参考一

 type MyStruct struct {
        N int
    }
    n := MyStruct{ 1 }

    // get 
    immutable := reflect.ValueOf(n)
    val := immutable.FieldByName("N").Int()
    fmt.Printf("N=%d\n", val) // prints 1

    // set
    mutable := reflect.ValueOf(&n).Elem()
    mutable.FieldByName("N").SetInt(7)
    fmt.Printf("N=%d\n", n.N) // prints 7
    

参考二

type Person struct {
    Name   string  `json:"name"`
    Age       int   `json:"age"`
}

func SetValueToStruct(name string,age int) *Person {
        p := &Person{}
        v := reflect.ValueOf℗.Elem()
        v.FieldByName("Name").Set(reflect.ValueOf(name))
        v.FieldByName("Age").Set(reflect.ValueOf(age))
        return p
}


func main()  {
    p := SetValueToStruct("张三",18)
    fmt.Println(*p)
}

注:可能出现的错误

1.结构体首字母必须大写,否则会出现:panic: reflect: reflect.Value.Set using value obtained using unexported field
在Golang中首字母的大小写代表着访问权限,首字母小写则包外无法访问
2. 反射需要使用地址 否则会出现:panic: reflect: reflect.Value.Set using unaddressable value
如下代码就会出现panic

p := Person{}
v := reflect.ValueOf℗
v.FieldByName("Name").Set(reflect.ValueOf(name))
v.FieldByName("Age").Set(reflect.ValueOf(age))

2019/5/3 文章分类: GO语言技巧

有点不安全却又一亮的 Go unsafe.Pointer

在上一篇文章 《深入理解 Go Slice》 中,大家会发现其底层数据结构使用了 unsafe.Pointer。因此想着再介绍一下其关联知识。

前言

在大家学习 Go 的时候,肯定都学过 “Go 的指针是不支持指针运算和转换” 这个知识点。为什么呢?

首先,Go 是一门静态语言,所有的变量都必须为标量类型。不同的类型不能够进行赋值、计算等跨类型的操作。那么指针也对应着相对的类型,也在 Compile 的静态类型检查的范围内。同时静态语言,也称为强类型。也就是一旦定义了,就不能再改变它。

错误示例

func main(){
    num := 5
    numPointer := &num

    flnum := (*float32)(numPointer)
    fmt.Println(flnum)
}

输出结果:

# command-line-arguments
...: cannot convert numPointer (type *int) to type *float32

在示例中,我们创建了一个 num 变量,值为 5,类型为 int。取了其对于的指针地址后,试图强制转换为 *float32,结果失败...

unsafe

针对刚刚的 “错误示例”,我们可以采用今天的男主角 unsafe 标准库来解决。它是一个神奇的包,在官方的诠释中,有如下概述:

  • 围绕 Go 程序内存安全及类型的操作

  • 很可能会是不可移植的

  • 不受 Go 1 兼容性指南的保护

简单来讲就是,不怎么推荐你使用。因为它是 unsafe(不安全的),但是在特殊的场景下,使用了它。可以打破 Go 的类型和内存安全机制,让你获得眼前一亮的惊喜效果。

Pointer

为了解决这个问题,需要用到 unsafe.Pointer。它表示任意类型且可寻址的指针值,可以在不同的指针类型之间进行转换(类似 C 语言的 void * 的用途)

其包含四种核心操作:

  • 任何类型的指针值都可以转换为 Pointer

  • Pointer 可以转换为任何类型的指针值

  • uintptr 可以转换为 Pointer

  • Pointer 可以转换为 uintptr

在这一部分,重点看第一点、第二点。你再想想怎么修改 “错误示例” 让它运行起来?

func main(){
    num := 5
    numPointer := &num

    flnum := (*float32)(unsafe.Pointer(numPointer))
    fmt.Println(flnum)
}

输出结果:

0xc4200140b0

在上述代码中,我们小加改动。通过 unsafe.Pointer 的特性对该指针变量进行了修改,就可以完成任意类型(*T)的指针转换。

需要注意的是,这时还无法对变量进行操作或访问。因为不知道该指针地址指向的东西具体是什么类型。不知道是什么类型,又如何进行解析呢。无法解析也就自然无法对其变更了

Offsetof

在上小节中,我们对普通的指针变量进行了修改。那么它是否能做更复杂一点的事呢?

type Num struct{
    i string
    j int64
}

func main(){
    n := Num{i: "EDDYCJY", j: 1}
    nPointer := unsafe.Pointer(&n)

    niPointer := (*string)(unsafe.Pointer(nPointer))
    *niPointer = "煎鱼"

    njPointer := (*int64)(unsafe.Pointer(uintptr(nPointer) + unsafe.Offsetof(n.j)))
    *njPointer = 2

    fmt.Printf("n.i: %s, n.j: %d", n.i, n.j)
}

输出结果:

n.i: 煎鱼, n.j: 2

在剖析这段代码做了什么事之前,我们需要了解结构体的一些基本概念:

  • 结构体的成员变量在内存存储上是一段连续的内存

  • 结构体的初始地址就是第一个成员变量的内存地址

  • 基于结构体的成员地址去计算偏移量。就能够得出其他成员变量的内存地址

再回来看看上述代码,得出执行流程:

  • 修改 n.i 值:i 为第一个成员变量。因此不需要进行偏移量计算,直接取出指针后转换为 Pointer,再强制转换为字符串类型的指针值即可

  • 修改 n.j 值:j 为第二个成员变量。需要进行偏移量计算,才可以对其内存地址进行修改。在进行了偏移运算后,当前地址已经指向第二个成员变量。接着重复转换赋值即可

需要注意的是,这里使用了如下方法(来完成偏移计算的目标):

1、uintptr:uintptr 是 Go 的内置类型。返回无符号整数,可存储一个完整的地址。后续常用于指针运算

type uintptr uintptr

2、unsafe.Offsetof:返回变量的字节大小,也就是本文用到的偏移量大小。需要注意的是入参 ArbitraryType 表示任意类型,并非定义的 int。它实际作用是一个占位符

func Offsetof(x ArbitraryType) uintptr

在这一部分,其实就是巧用了 Pointer 的第三、第四点特性。这时候就已经可以对变量进行操作了

错误示例

func main(){
    n := Num{i: "EDDYCJY", j: 1}
    nPointer := unsafe.Pointer(&n)
    ...

    ptr := uintptr(nPointer)
    njPointer := (*int64)(unsafe.Pointer(ptr + unsafe.Offsetof(n.j)))
    ...
}

这里存在一个问题,uintptr 类型是不能存储在临时变量中的。因为从 GC 的角度来看,uintptr 类型的临时变量只是一个无符号整数,并不知道它是一个指针地址

因此当满足一定条件后,ptr 这个临时变量是可能被垃圾回收掉的,那么接下来的内存操作,岂不成迷?

总结

简洁回顾两个知识点。第一是 unsafe.Pointer 可以让你的变量在不同的指针类型转来转去,也就是表示为任意可寻址的指针类型。第二是 uintptr 常用于与 unsafe.Pointer 打配合,用于做指针运算,巧妙地很。

最后还是那句话,没有特殊必要的话。是不建议使用 unsafe 标准库,它并不安全,虽然它常常能让你眼前一亮。

2019/5/3 文章分类: GO语言技巧

go-micro的项目实战

  1. consul的开发状态的命令

consul agent -dev

  1. micro的测试命令

micro --registry=consul call xsoft.go.mes.auth AuthService.CheckUserWithPwd '{"username":"houqun-hahahah", "password":"12345"}'

micro --registry=consul call xsoft.go.mes.auth AuthService.GetUserOneByUsername '{"username":"admin", "password":"123456"}'

  1. 安装protobuf
go get github.com/micro/protobuf/{proto,protoc-gen-go}

# install protoc-gen-micro
go get -u github.com/micro/protoc-gen-micro

  1. 安装go-micro
go get github.com/micro/go-micro

  1. 安装micro
go get github.com/micro/micro

  1. proto3 生成的文件 包含 const _ = proto.ProtoPackageIsVersion2

(1)检查protoc版本

protoc --version
libprotoc 3.7.0

看看版本是不是3.x.x以上
如果是的,那么多半是protoc-gen-go 没升级

linux下 来取最新的 github.com/golang/protobuf

go get github.com/golang/protobuf
echo $GOPATH
cd $GOPATH/github.com/golang/protobuf/protoc-gen-go
go build 

然后把生成的二进制文件 protoc-gen-go 拷贝到protoc 所在目录下 或者把protoc-gen-go 所在目录加入到环境变量中

查看protoc所在目录

which protoc

2019/5/1 文章分类: Go语言项目

使用beego的ParseForm把form数据解析成Struct时,部分数据解析不出来

经过一番查找,User字段中,有个关联的字段,使用的RoleIds []int64,这个数据解析不出来。

后来调整成RoleIds []int,数据就能够解析出来了。

虽然问题找到并解决了,但是不清楚问题的真实原因是什么,后续需要仔细的研究。

2018/8/20 文章分类: GO语言错误处理

设置Mac终端提示符颜色以及设置golang环境变量

设置Mac终端提示符颜色


export LS_OPTIONS='--color=auto' # 如果没有指定,则自动选择颜色
export CLICOLOR=1 #是否输出颜色
export LSCOLORS='Exfxcxdxbxegedabagacad' #指定颜色
export PS1='\[\033[01;33m\]\u@\h\[\033[01;31m\] \W\$\[\033[00m\] '

阅读全文   2018/8/17 文章分类: 操作系统相关

阿里云服务上,gogs的安装与迁移

之前在一台阿里云服务器上装了gogs,作为个人的代码管理工具。

这台阿里云服务器到期,换了一台新的阿里云服务器,就需要在新服务器上安装gogs,且要把原服务器上的gogs的数据迁移到新服务器上。

这里记录这个迁移过程,留作以后参考备用。

阅读全文   2018/8/17 文章分类: Go语言项目

跨平台交叉编译Go程序

作用:比如你手头只有Mac系统,而你的用户有Linux和Windows的,他们也想用,你可以通过交叉编译出Linux和Windows上的可执行文件给他们用

阅读全文   2018/8/14 文章分类: GO语言技巧

go run main.go杀掉进程的方法

可以通过下面的命令来处理:


lsof -i tcp:端口号

kill PID 

也可以通过下面的命令来处理:


killall -9 main

其中的main,就是main.go运行之后的进程名称。

2018/8/12 文章分类: GO语言技巧

golang安装gRPC

gRPC安装官方安装命令:

go get google.golang.org/grpc

这个安装命令是有问题的,会报:

package google.golang.org/grpc: unrecognized import path "google.golang.org/grpc"(https fetch: Get https://google.golang.org/grpc?go-get=1: dial tcp 216.239.37.1:443: i/o timeout)

阅读全文   2018/8/5 文章分类: GO语言第三方包

阿里云vps上mysql挂掉的解决办法

用阿里云的vps用作blog服务器,系统很稳定,已经100多天一直运行正常,大概从上个月开始发现blog的mysql会有时挂掉,会收到短信通知。之前没太追究,重新启动了mysql解决的。今天上午又收到短信,已经第三次了。

查了一下日志,三次基本都是一样的:

阅读全文   2017/12/20 文章分类: 数据库相关

Linux 下压缩与解压缩命令

tar

-c: 建立压缩档案
-x:解压
-t:查看内容
-r:向压缩归档文件末尾追加文件
-u:更新原压缩包中的文件

这五个是独立的命令,压缩解压都要用到其中一个,可以和别的命令连用但只能用其中一个。下面的参数是根据需要在压缩或解压档案时可选的。

阅读全文   2017/6/26 文章分类: 操作系统相关