Famous Libraries Explained
goconfig
A configuration file parser for the common INI format under Windows for the Go language. This parser not only covers all INI file operations but also extends to meet some requirements encountered during actual Go language development. The biggest advantage of this parser is its excellent support for comments. In addition, supporting the overlay loading of multiple configuration files is also a very special yet useful feature.
- Provides operations identical to Windows API
- Supports recursive section reading
- Supports auto-incrementing key names
- Supports read and write operations for comments
- Supports direct return of key values of specified types
- Supports overlay loading of multiple files
Installation
- gopm
gopm get github.com/Unknwon/goconfig- go get
go get github.com/Unknwon/goconfig- doc
Basic Usage
; conf.ini
; Google
google = www.google.com
search = http://%(google)s
; Here are Comments
; Second line
[Demo]
# This symbol can also make this line to be comments
key1 = Let's us goconfig!!!
key2 = test data
key3 = this is based on key2:%(key2)s
quote = "special case for quote
"key:1" = This is the value of "key:1"
"key:2=key:1" = this is based on "key:2=key:1" => %(key:1)s
中国 = China
chinese-var = hello %(中国)s!
array_key = 1,2,3,4,5
[What's this?]
; Not Enough Comments!!
name = try one more value ^-^
empty_value =
[url]
google_fake = www.google.fake
google_url = http://%(google_fake)s
[parent]
name = john
relation = father
sex = male
age = 32
money = 1.25
[parent.child]
age = 3
married = true
[parent.child.child]
; Auto increment by setting key to "-"
[auto increment]
- = hello
- = go
- = config
package main
import (
"github.com/Unknwon/goconfig"
)
// 加载配置文件
cfg,err:=goconfig.LoadConfigFile("conf.ini")
if err!=nil {
log.Fatalf("无法加载配置文件:%s",err)
}
// 基本读写操作
value,err:=cfg.GetValue(goconfig.DEFAULT_SECTION,"key_default")
isInsert:=cfg.SetValue(goconfig.DEFAULT_SECTION,"key_devault","这是新的值")
package main
import (
"fmt"
"github.com/Unknwon/goconfig"
"log"
)
func main() {
cfg,err := goconfig.LoadConfigFile("conf.ini")
if err!=nil {
log.Fatalf("无法加载配置文件:%s",err)
}
value,err:=cfg.GetValue("Demo","key1")
if err!=nil {
log.Fatalf("无法获取值{%s}:%s","Demo",err)
}
fmt.Printf("%s -> %s : %s","Demo","key1",value)
}
// 注释 分区注释 键注释
comment:=cfg.GetSectionComments("super") //获取分区注释
log.Printf("分区 %s 的注释:%s","super",comment)
v:=cfg.SetSectionComments("super","# 这是新的分区注释") // 井号保留
- Type conversion reading
vInt,err:=cfg.Int("must","int")// Section key value- Must series methods
vBool:=cfg.MustBool("must","bool")- Delete specified key value
ok:=cfg.DeleteKey("must","string")- Save configuration file
err=goconfig.SaveConfigFile(cfg,"conf_save.ini")
Advanced Usage
- Multiple file overlay loading
cfg,err:=goconfig.LoadConfigFile("conf.ini","conf2.ini")err = cfg.AppendFiles("conf3.ini")- Configuration file reload
err = cfg.Reload()- It will load in the previous multiple order.
- Set default values for Must system methods
vBool:=cfg.MustBool("must","bool404",true)- Recursive key value reading
- Sub-sections only need to set different values; identical ones do not need to be set (sub-sections are separated by
.) - Automatic key name retrieval, retrieve the entire section (auto-incrementing key names are set with
-) sec,err:=cfg.GetSection("auto increment")
; 键值必须是先声明过的,使用%(键名)s
google=www.google.com
search=http://%(goole)s
xorm Basic Usage
- Bidirectional mapping and incremental synchronization between structs and database tables
- Chained method calls
- Session transactions and rollbacks
- Mixed transactions with ORM methods and raw SQL
- LRU-based cache
- Database table optimistic locking
gopm get github.com/go-xorm/xorm
# 或使用go get安装
go get github.com/go-xorm/xorm
In Go language, ORM typically defines models directly based on struct definitions, combined with tags.
type Account struct {
Id int64
Name string `xorm:"unique"` // tag
Balance float64
Version int `xorm:"version"` //乐观锁
}
Create two files: main.go and models.go
// main.go
/* 1. 导入数据库驱动包 这里以sqlite为例
a. go get github.com/go-xorm/xorm
b. go get github.com/mattn/go-sqlite3
c. 导入驱动包 import(
_ "github.com/mattn/go-sqlite3" // 因为导入的包必须使用所以要用个占位,只执行这个包的初始化函数
)
*/
package main
import (
"fmt"
"xorm"
)
const prompt = `Please enter number of operation:
1. Create new account
2. Show detail of account
3. Deposit
4. Withdraw
5. Make transfer
6. List account by Id
7. List account by balance
8. Delete account
9. Exit`
func main() {
fmt.Println("Welcome bank of xorm!")
Exit:
for {
fmt.Println(prompt)
var num int
fmt.Scanf("%d\n", &num) //回车
switch num {
case 1:
fmt.Println("Place enter <name> <balance>:")
var name string
var balance float64
fmt.Scanf("%s %f\n", &name, &balance)
if err := xorm.NewAccount(name, balance); err != nil {
fmt.Println(err)
}
case 2:
fmt.Println("Place enter <id>:")
var id int64
fmt.Scanf("%d\n", &id)
a, err := xorm.GetAccount(id)
if err != nil {
fmt.Println(err)
} else {
fmt.Printf("%#v", a)
}
case 3:
fmt.Printf("Please enter <id> <deposit>: ")
var id int64
var deposit float64
fmt.Scanf("%d %f\n", &id, &deposit)
a, err := xorm.MakeDeposit(id, deposit)
if err != nil {
fmt.Println(err)
} else {
fmt.Printf("%#v", a)
}
case 4:
fmt.Printf("Please enter <id> <withdraw>: ")
var id int64
var withdraw float64
fmt.Scanf("%d %f\n", &id, &withdraw)
a, err := xorm.MakeWithdraw(id, withdraw)
if err != nil {
fmt.Println(err)
} else {
fmt.Printf("%#v", a)
}
case 5:
fmt.Printf("Please enter <id> <balance> <id>")
var id1, id2 int64
var balance float64
fmt.Scanf("%d %f %d", &id1, &balance, &id2)
if err := xorm.MackTransfer(id1, id2, balance); err != nil {
fmt.Println(err)
}
case 6:
as, err := xorm.GetAccountAscId("id")
if err != nil {
fmt.Println(err)
} else {
for i, a := range as {
fmt.Printf("%d %#v\n", i, a)
}
}
case 7:
as, err := xorm.GetAccountAscId("balance")
if err != nil {
fmt.Println(err)
} else {
for i, a := range as {
fmt.Printf("%d %#v\n", i, a)
}
}
case 8:
fmt.Println("Place enter <id>:")
var id int64
fmt.Scanf("%d\n", &id)
if err := xorm.DeleteAccount(id);err!=nil {
fmt.Println(err)
}
case 9:
break Exit
}
}
}
// models.go
/*
注意:每个golang源文件中都可以定义一个init函数。golang系统中,所有的源文件都有自己所属的目录,每一个目录都有对应的包名。在包的引用中,一旦某一个包被使用,则这个包下边的init函数将会被执行,且只执行一次。
1. 新建
_,err:=x.Insert(&Account{Name:name,Balance:balance})
2. 删除
_,err:=
3. 获取并修改
a:=&Account{}
has,err:=x.Id(id).Get(a)
a.Balance+=deposit
_,err = x.Update(a)
4. 原始的事务操作 通过version判断。
*/
package xorm
import (
"errors"
"github.com/go-xorm/xorm"
_ "github.com/mattn/go-sqlite3"
"log"
)
type Account struct {
Id int64 //默认主键 如果指定其它为主键则要加tag `xorm:"pk"`
Name string //`xorm:"unique"` // tag
Balance float64
Version int `xorm:"version"` //乐观锁
}
var x *xorm.Engine
func init() {
var err error
x, err = xorm.NewEngine("sqlite3", "./bank.db") // xorm.NewEngine{"sqlite3","./bank.db"}
if err != nil {
log.Fatalf("Fail to create engine %v", err)
}
if err = x.Sync(new(Account)); err != nil {
log.Fatalf("Fal to sync database: %v", err)
}
}
func NewAccount(name string, balance float64) error {
//新增记录
_, err := x.Insert(&Account{Name: name, Balance: balance})
return err
}
// 获取记录
func GetAccount(id int64) (*Account, error) {
a := &Account{} //
has, err := x.Id(id).Get(a)
if err != nil {
return nil, err
} else if !has {
return nil, errors.New("Account not found")
}
return a, nil
}
//存款
func MakeDeposit(id int64, deposit float64) (*Account, error) {
//a := &Account{}
a, err := GetAccount(id)
if err != nil {
return nil, err
}
a.Balance += deposit
_, err = x.Update(a)
return a, err
}
//取款
func MakeWithdraw(id int64, withDraw float64) (*Account, error) {
//a := &Account{}
a, err := GetAccount(id)
if err != nil {
return nil, err
}
if a.Balance <= withDraw {
return nil, errors.New("Not enough balance")
}
a.Balance -= withDraw
_, err = x.Update(a)
return a, err
}
//转帐
func MackTransfer(id1, id2 int64, balance float64) error {
a1, err := GetAccount(id1)
if err != nil {
return err
}
a2, err := GetAccount(id2)
if err != nil {
return err
}
if a1.Balance < balance {
return errors.New("Not enough balance")
}
a1.Balance -= balance
a2.Balance += balance
if _, err = x.Update(a1); err != nil {
return err
} else if _, err = x.Update(a2); err != nil {
return err
}
return nil
}
//批量获取
/*
err = x.Desc("balance").Find(&as) //入一个slice的地址
*/
func GetAccountAscId(orderBy string) (as []*Account, err error) {
err = x.Asc(orderBy).Find(&as)
return as, err
}
//delete
func DeleteAccount(id int64) error {
_, err := x.Delete(&Account{Id: id})
return err
}
xorm Advanced Usage
Transactions and Rollbacks
- Create session object
- Start transaction
- Operate database via session
- Rollback on error
- Commit transaction
// 1.
sess:=x.NewSession()
// 2.
sess.Begin()
// 3.
sess.Update()
// 4.
sess.RollBack()
// 5.
sess.Commit()
Modify the transfer operation in the previous example
//转帐
func MackTransfer(id1, id2 int64, balance float64) error {
a1, err := GetAccount(id1)
if err != nil {
return err
}
a2, err := GetAccount(id2)
if err != nil {
return err
}
if a1.Balance < balance {
return errors.New("Not enough balance")
}
a1.Balance -= balance
a2.Balance += balance
//if _, err = x.Update(a1); err != nil {
// return err
//} else if _, err = x.Update(a2); err != nil {
// return err
//}
//return nil
// 创建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
} else if _, err = sess.Update(a2); err != nil {
sess.Rollback()
return err
}
// 提交事务
return sess.Commit()
}
Count records
x.Count(new(Accout))
// 配合链式操作
x.Where("id>10").Count(new(Account))
Iterative Query
- Iteratively query all records in a table that meet the conditions
- Use Rows object
// 迭代查询
x.Iterate(new(Account),func(idx int,bean interface{}){
fmt.Printf("%d,%#v\n",idx,bean.(*Account))
})
// Rows
func GetRows() {
a := new(Account)
rows, err := x.Rows(new(Account))
if err != nil {
log.Fatalf("Fail to get row:%v\n", err)
}
defer rows.Close()
for rows.Next() {
if err = rows.Scan(a); err != nil {
log.Fatalf("Fail to get row:%v\n", err)
}
fmt.Printf("%#v\n", a)
}
}
// main.go
package main
import (
"fmt"
"log"
"xorm"
)
type Account xorm.Account
func main() {
fmt.Println("Welcome to bank of xorm2!")
count, err := xorm.GetNum()
if err != nil {
log.Fatalf("Fail to get account count: %v\n", err)
}
fmt.Println("Account count: ", count)
for i := count; i < 10; i++ {
if err = xorm.NewAccount(fmt.Sprintf("joe%d", i), float64(i)*100); err != nil {
log.Fatalf("Fail to create account %v\n", err)
}
}
// 迭代查询
fmt.Println("Query all recores:")
xorm.It()
fmt.Println("==== Query all recores by Rows:====")
xorm.GetRows()
}
// models.go /src/xorm/models.go 新增这几个方法
// Iterator 迭代
func It() {
x.Iterate(new(Account), printFn)
}
var printFn = func(idx int, bean interface{}) error {
fmt.Printf("%d:%v\n", idx, bean.(*Account))
return nil
}
func GetRows() {
a := new(Account)
rows, err := x.Rows(new(Account))
if err != nil {
log.Fatalf("Fail to get row:%v\n", err)
}
defer rows.Close()
for rows.Next() {
if err = rows.Scan(a); err != nil {
log.Fatalf("Fail to get row:%v\n", err)
}
fmt.Printf("%#v\n", a)
}
}
Common Query Methods
- When only the value of a specific field in the struct is valuable to you
x.Cols("name").Iterate(new(Account),...)- When you want to intentionally ignore a field in the query result
x.Omit("name").Iterate(new(Account)...)- Query result offset, most common in pagination applications
x.Limit(3,2).Iterate(new(Account),...)
func GetNameCol() {
x.Cols("name").Iterate(new(Account),printFn)
}
func ExcludeCol() {
x.Omit("name").Iterate(new(Account),printFn)
}
Logging Functionality
- Enable logging
x.ShowSQL = true- Save logs to file
f,err:=os.Create("sql.log")
if err!=nil {
log.Fatalf("Fail to create log file:%v\n",err)
return
}
xorm.NewSimpleLogger(f)
logger:= xorm.NewSimpleLogger(f)
logger.ShowSQL(true) // 和教程不一样,这块需求注意
x.SetLogger(logger)
LRU Cache
Set default LRU cache
cacher:=xorm.NewLRUCacher(xorm.NewMemoryStore(),1000)
x.SetDefaultCacher(cacher)
Event Hooks
Officially provides 6 types
- BeforeInsert
- AfterInsert
- BeforeUpdate
- AfterUpdate
- BeforeDelete
- AfterDelete
// 作为方法调用
func (a *Account) BeforeInsert(){
log.Printf("before insert %s", a.Name)
}
func (a *Account) AfterInsert(){
log.Printf("after insert %s", a.Name)
}
Notable Cases
GogsGo WalkerGoBuild.IOSudo China
GoConvery
- Elegant and concise test code
- Direct integration with Go native testing
- Fully automatic compilation and testing
- Detailed display of test structure and coverage
- Highly readable command-line output
- Semi-automated test writing
GoConvery Installation
- gopm installation
gopm get github.com/smartystreets/goconvey- go get
go get github.com/smartystreets/goconvey
Use a simple example to implement 4 arithmetic functions for testing.
// main.go 一般不会命名为main包,可做单元测试的包一般都是可做重复利用的包,一般情况下main包不太可能会做重复利用
package goconvey
import "errors"
func Add(a, b int) int {
return a + b
}
func Substract(a, b int) int {
return a - b
}
func Multiply(a, b int) int {
return a * b
}
func Division(a, b int) (int, error) {
if b == 0 {
return 0, errors.New("被除数为0!")
}
return a / b, nil
}
Writing Tests
//引入两个包 testing和github.com/smartystreets/goconvey/convey
package goconvey
import (
. "github.com/smartystreets/goconvey/convey"
"testing"
)
func TestAdd(t *testing.T) {
Convey("将两数相加", t, func() {
So(Add(1, 2), ShouldEqual, 3)
})
}
func TestSubstract(t *testing.T) {
Convey("将两数相减", t, func() {
So(Substract(1, 2), ShouldEqual, -1)
})
}
func TestMultiply(t *testing.T) {
Convey("将两数相乘", t, func() {
So(Multiply(3, 2), ShouldEqual, 6)
})
}
func TestDivision(t *testing.T) {
Convey("将两数相除", t, func() {
// 嵌套Convery 除0和不除0情况
//注意嵌套的不用传t参数
Convey("被除数为0", func() {
_, err := Division(10, 0)
So(err, ShouldNotBeNil)
})
Convey("除数不为0", func() {
num, err := Division(10, 2)
So(err, ShouldBeNil)
So(num, ShouldEqual, 5)
})
})
}
There are two testing methods:
One is using go test as shown below:
There are as many dots as there are Convey blocks. You can also use go test -v for richer content.
Another method is to install a test coverage tool:
go get code.google.com/p/go.tools/cmd/cover- In the test directory, type
goconvey. Pay attention to GOPATH settings.
Macaron Web Framework
- Supports flexible and diverse routing rules and combination patterns
- Supports unlimited routing middleware and infinite nesting
- Supports direct integration of existing services
- Supports dynamic setting of template sets to be rendered at runtime
- Supports easy integration and removal of modules
- Provides convenient dependency injection services
-
Uses a better routing layer and less reflection to improve execution speed
-
gopm installation
gopm get github.com/Unknwon/macaron- Install via go get
go get github.com/Unknwon/macaron
The Macaron framework was refined and developed from the Gogs project because during the development of Gogs, a large number of auxiliary modules were created that could be reused in other projects, thus, the idea of creating a new framework to improve code reusability emerged.
主题测试文章,只做测试使用。发布者:Walker,转转请注明出处:https://walker-learn.xyz/archives/6715
