Programming Fundamentals 0002_Explanation of Key Libraries

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 Gogs Go Walker GoBuild.IO Sudo 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:

Programming Fundamentals 0002_Explanation of Key Libraries

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

Official Website

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

(0)
Walker的头像Walker
上一篇 12 hours ago
下一篇 Nov 25, 2025 07:00

Related Posts

EN
简体中文 繁體中文 English