只执行选择的 case 所以不需要 break 语句,case 判断可以是变量

package main

import (
"fmt"
"runtime"
)

func main() {
fmt.Print("Go runs on ")
switch os := runtime.GOOS; os {
case "darwin":
fmt.Println("OS X.")
case "linux":
fmt.Println("Linux.")
default:
// freebsd, openbsd,
// plan9, windows...
fmt.Printf("%s.\n", os)
}
}

switch和java,c等的有不同的地方,使用上需要注意

不需要使用break,默认每个case是独立执行的

switch ch {
case '0':
cl = "Int"
case '1':
cl = "Int"
case 'A':
cl = "ABC"
break //可以添加
case 'a':
cl = "ABC"
default:
cl = "Other Char"
}

需要执行下一条case的情况,使用 fallthrough 语句,’0’和’1’都会执行cl=”Int”。

switch ch {
case '0':
fallthrough //必须是最后一个语句
case '1':
cl = "Int"
case 'A':
case 'a':
fallthrough
cl = "ABC" //error
default:
cl = "Other Char"
}

有多个匹配结果执行同一段处理的情况

switch ch {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
cl = "Int"
case 'A', 'B', 'C', 'D', 'a', 'b', 'c', 'd', 'e':
cl = "ABC"
default:
cl = "Other Char"
}

在 Case 中使用布尔表达式

switch {
case '0' <= ch && ch <= '9':
cl = "Int"
case ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z'):
cl = "ABC"
default:
cl = "Other Char"
}

proto file

syntax = "proto3";

package apiService;

service apiService {
rpc apiTrans(Request) returns (Response) {}
}

message Request {
string value = 1;
}

message Response {
string value = 1;
}

source code

package main

import (
"context"
"google.golang.org/grpc"
"google.golang.org/grpc/reflection"
"log"
"net"
pb "rpcServer/rpc_api"
)

const (
port = ":52061"
)

type server struct{}

// SayHello implements helloworld.GreeterServer
func (s *server) ApiTrans(ctx context.Context, in *pb.Request) (*pb.Response, error) {
log.Println("receive: ",in.Value)
return &pb.Response{Value:in.Value},nil
}

func RpcServe() {
listen, err := net.Listen("tcp", port)
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
s := grpc.NewServer()
pb.RegisterApiServiceServer(s, &server{})
// Register reflection service on gRPC server.
reflection.Register(s)
if err := s.Serve(listen); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}

func main() {
RpcServe()
}

implement a grpc server

define proto file

request a json string respoinse a json string

syntax = "proto3";

package apiService;

service apiService {
rpc apiTrans(Request) returns (Response) {}
}

message Request {
string value = 1;
}

message Response {
string value = 1;
}

generate cpp file

protoc --cpp_out=. rpc_api.proto

source code

class ApiService : public apiService::apiService::Service
{
// 构造、析构
public:

// 接口实现
public:
virtual ::grpc::Status apiTrans(::grpc::ServerContext* context,
const ::apiService::Request* request, ::apiService::Response* response) override
{
string strJson = request->value();
OutputDebugStringA(strJson.c_str());

response->set_value(strJson);
return grpc::Status::OK;
}
};

void rpcServer()
{
std::string server_address("0.0.0.0:52061");

ApiService service;

grpc::ServerBuilder builder;
builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
builder.RegisterService(&service);

std::unique_ptr<grpc::Server> server(builder.BuildAndStart());

std::cout << "Server listening on " << server_address << std::endl;

server->Wait();
}

tags

tag 说明 样例
column 自定义字段名 自定义 gorm:"column:f_id;"
type 字段类型 gorm:"type:varchar(20);" gorm:"type:integer(8);"
type Like struct {
ID int `gorm:"column:f_id;primary_key"`
Ip string `gorm:"type:varchar(20);not null;index:ip_idx"`
Ua string `gorm:"type:varchar(256);not null;"`
Title string `gorm:"type:varchar(128);not null;index:title_idx"`
Hash uint64 `gorm:"unique_index:hash_idx;"`
CreatedAt time.Time
}

连接

mysql

import (
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"

var db *gorm.DB
func init() {
var err error
db, err = gorm.Open("mysql", "<user>:<password>/<database>?charset=utf8&parseTime=True&loc=Local")
if err != nil {
panic(err)
}
}

sqlite

import (
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/sqlite"
)

var db *gorm.DB

func main() {
var err error
db, err = gorm.Open("sqlite3", "/tmp/gorm.db")
defer db.Close()
}

PostgreSQL

import (
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/postgres"
)
var db *gorm.DB

func main() {
var err error
db, err := gorm.Open("postgres", "host=myhost user=gorm dbname=gorm sslmode=disable password=mypassword")
defer db.Close()
}

错误处理

执行任何操作后,如果发生任何错误,GORM将其设置为*DB的Error字段

if err := db.Where("name = ?", "jinzhu").First(&user).Error; err != nil {
// 错误处理...
}

// 如果有多个错误发生,用`GetErrors`获取所有的错误,它返回`[]error`
db.First(&user).Limit(10).Find(&users).GetErrors()

// 检查是否返回RecordNotFound错误
db.Where("name = ?", "hello world").First(&user).RecordNotFound()

if db.Model(&user).Related(&credit_card).RecordNotFound() {
// 没有信用卡被发现处理...
}

连接池

db.DB().SetMaxIdleConns(10)
db.DB().SetMaxOpenConns(100)

事务

// 开始事务
tx := db.Begin()

// 在事务中做一些数据库操作(从这一点使用'tx',而不是'db')
tx.Create(...)

// ...

// 发生错误时回滚事务
tx.Rollback()

// 或提交事务
tx.Commit()

样例

func CreateAnimals(db *gorm.DB) err {
tx := db.Begin()
// 注意,一旦你在一个事务中,使用tx作为数据库句柄

if err := tx.Create(&Animal{Name: "Giraffe"}).Error; err != nil {
tx.Rollback()
return err
}

if err := tx.Create(&Animal{Name: "Lion"}).Error; err != nil {
tx.Rollback()
return err
}

tx.Commit()
return nil
}

迁移

自动迁移仅仅会创建表,缺少列和索引,并且不会改变现有列的类型或删除未使用的列以保护数据。

db.AutoMigrate(&User{})

db.AutoMigrate(&User{}, &Product{}, &Order{})

// 创建表时添加表后缀
db.Set("gorm:table_options", "ENGINE=InnoDB").AutoMigrate(&User{})

创建表

默认创建表回添加 s 在末尾,可以使用下面语句关闭

db.SingularTable(true) //全局设置表名不可以为复数形式。
// 为模型`User`创建表
db.CreateTable(&User{})

// 创建表`users'时将“ENGINE = InnoDB”附加到SQL语句
db.Set("gorm:table_options", "ENGINE=InnoDB").CreateTable(&User{})

索引

// 为`name`列添加索引`idx_user_name`
db.Model(&User{}).AddIndex("idx_user_name", "name")

// 为`name`, `age`列添加索引`idx_user_name_age`
db.Model(&User{}).AddIndex("idx_user_name_age", "name", "age")

// 添加唯一索引
db.Model(&User{}).AddUniqueIndex("idx_user_name", "name")

// 为多列添加唯一索引
db.Model(&User{}).AddUniqueIndex("idx_user_name_age", "name", "age")

// 删除索引
db.Model(&User{}).RemoveIndex("idx_user_name")

表是否存在

// 检查模型`User`表是否存在
db.HasTable(&User{})

// 检查表`users`是否存在
db.HasTable("users")

删除表

// 删除模型`User`的表
db.DropTable(&User{})

// 删除表`users`
db.DropTable("users")

// 删除模型`User`的表和表`products`
db.DropTableIfExists(&User{}, "products")

设置默认表名

你可以通过定义DefaultTableNameHandler来设置默认表名的命名规则

gorm.DefaultTableNameHandler = func (db *gorm.DB, defaultTableName string) string  {
return "prefix_" + defaultTableName;
}

设置列名

下划线分割命名(Snake Case)的列名

type User struct {
ID uint // 列名为`id`
Name string // 列名为 `name`
Birthday time.Time // 列名为 `birthday`
CreatedAt time.Time // 列名为 `created_at`
}

// 重写列名
type Animal struct {
AnimalId int64 `gorm:"column:beast_id"` // 设置列名为 `beast_id`
Birthday time.Time `gorm:"column:day_of_the_beast"` // 设置列名为 `day_of_the_beast`
Age int64 `gorm:"column:age_of_the_beast"` //设置列名为 `age_of_the_beast`
}

Run Raw SQL

db.Exec("DROP TABLE users;")
db.Exec("UPDATE orders SET shipped_at=? WHERE id IN (?)", time.Now(), []int64{11,22,33})

// Scan
type Result struct {
Name string
Age int
}

var result Result
db.Raw("SELECT name, age FROM users WHERE name = ?", 3).Scan(&result)


db.Raw("select count(1) as total from user").Scan(&count)

修改列

// 修改模型`User`的description列的数据类型为`text`
db.Model(&User{}).ModifyColumn("description", "text")

删除列

// 删除模型`User`的description列
db.Model(&User{}).DropColumn("description")

//Install Library
go get github.com/go-xorm/xorm
//Xorm 命令行工具
go get github.com/go-xorm/cmd/xorm
// 数据库驱动
go get github.com/mattn/go-sqlite3
go get -u github.com/go-sql-driver/mysql

https://github.com/mattn/go-sqlite3
https://github.com/go-sql-driver/mysql

使用 xorm 命令行工具

sqlite3 先要编译一下 xorm

  1. cd to %GOPATH%/src/github.com/go-xorm/cmd/xorm
  2. run “go build -tags sqlite3”
  3. a new “xorm” will be generated at current dir
  4. copy the new “xorm” to %GOPATH%/bin
  5. run your “xorm reverse …” again. Done!

xorm reverse sqlite3 test.db templates/goxorm

名称映射规则

xorm内置了三种IMapper实现:core.SnakeMapper,core.SameMapper和core.GonicMapper
SnakeMapper支持struct为驼峰式命名,表结构为下划线命名之间的转换;
SameMapper支持结构体名称和对应的表名称以及结构体field名称与对应的表字段名称相同的命名

engine.SetMapper(core.SnakeMapper{})

| name | 当前field对应的字段的名称 |
| — | — | — |
| pk | 是否是Primary Key |
| name | 当前field对应的字段的名称 |
| autoincr | 是否是自增 |
| [not ]null 或 notnull | 是否可以为空 |
| unique | 是否是唯一 |
| index | 是否是索引 |
| extends | 应用于一个匿名成员结构体或者非匿名成员结构体之上
| - | 这个Field将不进行字段映射 |
| -> | Field将只写入到数据库而不从数据库读取 |
| <- | Field将只从数据库读取,而不写入到数据库 |
| created | Field将在Insert时自动赋值为当前时间 |
| updated | Field将在Insert或Update时自动赋值为当前时间 |
|deleted | Field将在Delete时设置为当前时间,并且当前记录不删除 |
| version | Field将会在insert时默认为1,每次更新自动加1 |
| default 0或default(0) | 设置默认值,紧跟的内容如果是Varchar等需要加上单引号 |
| json | 表示内容将先转成Json格式 |

连接数据库

import (
_ "github.com/mattn/go-sqlite3"
"github.com/go-xorm/xorm"
)

var engine *xorm.Engine

func main() {
var err error
engine, err = xorm.NewEngine("sqlite3", "./test.db")
}
import (
_ "github.com/go-sql-driver/mysql"
"github.com/go-xorm/xorm"
)

var engine *xorm.Engine

func main() {
var err error
engine, err = xorm.NewEngine("mysql", "root:123@/test?charset=utf8")
}

自动同步表结构

ync2会进行如下这些操作:

自动检测和创建表,这个检测是根据表的名字
自动检测和新增表中的字段,这个检测是根据字段名,同时对表中多余的字段给出警告信息
自动检测,创建和删除索引和唯一索引,这个检测是根据索引的一个或多个字段名,而不根据索引名称。因此这里需要注意,如果在一个有大量数据的表中引入新的索引,数据库可能需要一定的时间来建立索引。
自动转换varchar字段类型到text字段类型,自动警告其它字段类型在模型和数据库之间不一致的情况。
自动警告字段的默认值,是否为空信息在模型和数据库之间不匹配的情况

if err = x.Sync2(new(Account)); err != nil {
log.Fatalf("Fail to sync database: %v\n", err)
}

查询

results, err := engine.Query("select * from user")

// 注意这里首字母要大写,导出该字段,类型名和表名对应,字段名和表字段名对应
type T_user struct {
F_id int64 `xorm:"not null pk autoincr INT(11)"`
F_ui_id int64 `xorm:"INT(11)"`
F_group_id int64 `xorm:" INT(11)"`
F_pwd string `xorm:"not null VARCHAR(32)"`
F_name string `xorm:"not null VARCHAR(32)"`
}

// 根据结构体中存在的非空数据来获取单条数据
user := &T_user{F_name: "admin", F_pwd: "4acb4bc224acbbe3c2bfdcaa39a4324e"}
has, err := engine.Get(user)
fmt.Println(has)

// 根据where获取单条数据
user := new(User)
has, err := engine.Table("t_user").Where("f_name=? and f_pwd=?", "admin", "4acb4bc224acbbe3c2bfdcaa39a4324e").Get(user)
fmt.Println(has)

// 根据where获取单条数据
user := new(T_user)
has, err := engine.Where("f_name=? and f_pwd=?", "admin", "4acb4bc224acbbe3c2bfdcaa39a4324e").Get(user)
fmt.Println(has)

返回的结果为两个参数,一个has(bool类型)为该条记录是否存在,第二个参数err为是否有错误。不管err是否为nil,has都有可能为true或者false

根据Id来获得单条数据

has, err := x.Id(id).Get(a)

逐条执行查询到的记录

Iterate方法提供逐条执行查询到的记录的方法,他所能使用的条件和Find方法完全相同

err := x.Where("id > ?=)", 30).Iterate(new(Account), func(i int, bean interface{})error{
user := bean.(*Account)
//do somthing use i and user
})

我们主要来看迭代函数的声明:它接受 2 个参数,第一个是当前记录所对应的索引(该索引和 ID 的值毫无关系,只是查询后结果的索引),第二个参数则是保存了相关类型的空接口,需要自行断言,例如示例中使用 bean.(*Account) 因为我们知道查询的结构是 Account。

查询特定字段

使用 Cols 方法可以指定查询特定字段,当只有结构中的某个字段的值对您有价值时,就可以使用它:

x.Cols("name").Iterate(new(Account), printFn)

var printFn = func(idx int, bean interface{}) error {
//dosomething
return nil
}

此处,所查询出来的结构只有 Name 字段有值,其它字段均为零值。要注意的是,Cols 方法所接受的参数是数据表中对应的名称,而不是字段名称。

统计记录条数- Count方法

统计数据使用Count方法,Count方法的参数为struct的指针并且成为查询条件。

a := new(Account)
//返回满足id>1的Account的记录条数
total, err := x.Where("id >?", 1).Count(a)
// 返回Account所有记录条数
total,err = x.Count(a)

更新

affected, err := engine.Exec("update user set .... where ...")

// 在获取到记录之后,我们就需要进行一些修改,然后更新到数据库:
a.Balance += deposit
// 对已有记录进行更新
_, err = x.Update(a)

// 注意,Update接受的参数是指针

删除

方法 Delete 接受参数后,会自动根据传进去的值进行查找,然后删除。比如此处,我们指定了 Account 的 ID 字段,那么就会删除 ID 字段值与我们所赋值相同的记录;如果您只对 Name 字段赋值,那么 xorm 就会去查找 Name 字段值匹配的记录。如果多个字段同时赋值,则是多个条件同时满足的记录才会被删除。

删除操作针对的对象没有限制,凡是按照条件查找到的,都会被删除(单个与批量删除)。

_, err := x.Delete(&Account{Id: id})

if _, err := session.Exec("delete from userinfo where username = ?", user2.Username); err != nil {
return err
}

事务及回滚

// 创建 Session 对象
sess := x.NewSession()
defer sess.Close()
// 开启事务
if err = sess.Begin(); err != nil {
return err
}

if _, err = sess.Update(a1); err != nil {
// 发生错误时进行回滚
sess.Rollback()
return err
}

// 完成事务
return sess.Commit()

日志记录

一般情况下,使用x.ShowSQL = true来开启 xorm 最基本的日志功能,所有 SQL 都会被打印到控制台,但如果您想要将日志保存到文件,则可以在获取到 ORM 引擎之后,进行如下操作:

f, err := os.Create("sql.log")
if err != nil {
log.Fatalf("Fail to create log file: %v\n", err)
return
}
x.Logger = xorm.NewSimpleLogger(f)

LRU 缓存

只需要在获取到 ORM 引擎之后,进行如下操作
这样就算是使用最基本的缓存功能了。该功能还支持只缓存某些表或排除缓存某些表,详情可以参见 文章首部的官方文档。

cacher := xorm.NewLRUCacher(xorm.NewMemoryStore(), 1000)
x.SetDefaultCacher(cacher)

表操作

是否存在

// 通过结构体判断
{
exists, _ := engine.IsTableExist(&tOpLog{})
fmt.Println(exists)
}
// 通过表名字符串判断
{
exists, _ := engine.IsTableExist("t_123123")
fmt.Println(exists)
}

创建表自定义表名

type User struct {
ID int `xorm:"serial primary key 'id'"`
Name string `xorm:"text not null 'name'"`
Type string `xorm:"text not null 'type'"`
}

func (u *User) TableName() string {
return "users"
}

db, err := xorm.NewEngine("postgres", "postgres://db_admin:db_admin@db/sample_db?sslmode=disable")
db.CreateTables(&User{})

查看 MTU

netsh interface ipv4 show subinterfaces

TCP数据包每次能够传输的最大数据分段为MSS,为了达到最佳的传输效能,在建立TCP连接时双方协商MSS值,双方提供的MSS值的最小值为这次连接的最大MSS值。MSS往往基于MTU计算出来,通常MSS=MTU-sizeof(IP Header)-sizeof(TCP Header)=1500-20-20=1460。

这个据说经过优化,用了之后,发现需要安装 gcc ,然后debug的时候,后台在compiling,很久然后,out of memory,机器内存16G
https://github.com/struCoder/Go-pinyin

是基于这个优化后的
https://github.com/mozillazg/go-pinyin

import "github.com/mozillazg/go-pinyin"

/*
hans := "0123456789楼防区"
p1 := get_pin_yin(hans)
fmt.Println(p1)

return _0_1_2_3_4_5_6_7_8_9_lou_fang_qu
*/
func get_pin_yin(param string) string {
strRet := "_"
var strTail string
for _, val := range param {
if unicode.IsDigit(val) {
strRet += string(rune(val)) + "_"
} else {
strTail += string(rune(val))
}
}
a := pinyin.NewArgs()
pin := pinyin.Pinyin(strTail, a)

for _, val := range pin {
strRet += val[0] + "_"
}
strRet = strRet[:len(strRet)-1]
return strRet
}

正常在线安装会出现 mingw64 cannot get repository.txt 错误

Install chocolatey. Then type the following command line:

https://chocolatey.org/

需要 powershell 3.0; .net 4.5 wmf 5.1

# 查看 power shell 版本
(Get-Host).Version
choco install mingw

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

use vscode

/* 设置 GO111MODULE GO111MODULE 有三个值:off, on和auto(默认值)。

GO111MODULE=off,go命令行将不会支持module功能,寻找依赖包的方式将会沿用旧版本那种通过vendor目录或者GOPATH模式来查找。
GO111MODULE=on,go命令行会使用modules,而一点也不会去GOPATH目录下查找。
GO111MODULE=auto,默认值,go命令行将会根据当前目录来决定是否启用module功能。这种情况下可以分为两种情形:

当前目录在GOPATH/src之外且该目录包含go.mod文件
当前文件在包含go.mod文件的目录下面。

当modules 功能启用时,依赖包的存放位置变更为$GOPATH/pkg,允许同一个package多个版本并存,且多个项目可以共享缓存的 module。
*/

golang 提供了 go mod 命令来管理包。

命令 说明
download download modules to local cache(下载依赖包)
edit edit go.mod from tools or scripts(编辑go.mod
graph print module requirement graph (打印模块依赖图)
init initialize new module in current directory(在当前目录初始化mod)
tidy add missing and remove unused modules(拉取缺少的模块,移除不用的模块)
vendor make vendored copy of dependencies(将依赖复制到vendor下)
verify verify dependencies have expected content (验证依赖是否正确)
why explain why packages or modules are needed(解释为什么需要依赖)

创建一个新项目

在 GOPATH 目录之外新建一个目录,并使用 go mod init 初始化生成go.mod 文件
go.mod文件一旦创建后,它的内容将会被go toolchain全面掌控。go toolchain会在各类命令执行时,比如go get、go build、go mod等修改和维护go.mod文件。

项目名 hello

go mod init hello

执行 go run server.go 运行代码会发现 go mod 会自动查找依赖自动下载:
go module 安装 package 的原則是先拉最新的 release tag,若无tag则拉最新的commit,详见 Modules官方介绍。 go 会自动生成一个 go.sum 文件来记录 dependency tree:

goland

摘录至

在 GoLand 2019.1.3 中使用 Go Modules 需要进行两个设置:

Preferences -> Go -> Go Modules (vgo),勾选 Enable Go Modules (vgo) integration 以启用 Go Modules,并在 Proxy 输入框中输入 https://goproxy.io。如图所示:

20190916_142859.png

Preferences -> Go -> GOPATH,勾选上 Index entire GOPATH 以索引整个 GOPATH,不然无法导入包。如图所示:

20190916_142910.png

进行如上设置后,就可以在导入不在缓存中的包时,点击 Sync packages of… 下载该包了: