本文章会持续更新更多golang常用小技巧;
1. 单例模式
- 多用于只实例化一次,如配置模块,日志模块等;
package main
import (
"fmt"
"sync"
)
var cc *WebConfig
var once sync.Once
type WebConfig struct {
Port int `json:"port"`
}
func GetConfig() *WebConfig {
once.Do(func() {
cc = &WebConfig{Port: 8080}
})
return cc
}
func main() {
cfg1 := GetConfig()
cfg2 := GetConfig()
fmt.Println(cfg1 == cfg2)
}
复制代码
2. 函数执行超时控制
package main
import (
"fmt"
"time"
)
//1 .业务过程放到协程
// 2、把业务结果塞入channel
func job() chan string{
ret:=make(chan string)
go func() {
time.Sleep(time.Second*2)
ret<- "success"
}()
return ret
}
func run() (interface{}, error) {
c:=job()
select {
case r:=<-c:
return r,nil
case <-time.After(time.Second*3):
return nil,fmt.Errorf("time out")
}
}
func main() {
fmt.Println(run())
}
复制代码
3. 反射使用示例
- 主要理清楚
reflect.Kind
和reflect.Value
的用法
package main
import (
"fmt"
"reflect"
)
type User struct {
UserId int `name:"uid" bcd:"3456"`
UserName string
}
func Map2Struct(m map[string]interface{},u interface{}) {
v:=reflect.ValueOf(u)
if v.Kind()==reflect.Ptr{
v=v.Elem()
if v.Kind()!=reflect.Struct{
panic("must struct")
}
findFromMap:= func(key string,nameTag string ) interface {}{
for k,v:=range m{
if k==key || k==nameTag {
return v
}
}
return nil
}
for i:=0;i<v.NumField();i++{
get_value:=findFromMap(v.Type().Field(i).Name,v.Type().Field(i).Tag.Get("name"))
if get_value!=nil && reflect.ValueOf(get_value).Kind()==v.Field(i).Kind(){
v.Field(i).Set(reflect.ValueOf(get_value))
}
}
}else{
panic("must ptr")
}
}
func main() {
u:=&User{}
m:=map[string]interface{}{
"id":123,
"uid":101,
"UserName":"shenyi",
"age":19,
}
Map2Struct(m,u)
fmt.Printf("%+v", u)
}
复制代码
4. 构造函数技巧
- 作用是提高代码可维护性和阅读性,但是这种写法相对的会损失一些性能
package main
import (
"fmt"
)
type UserAttrFunc func(*User) //设置User属性的 函数类型
type UserAttrFuncs []UserAttrFunc
func(this UserAttrFuncs) apply(u *User) {
for _,f:=range this{
f(u)
}
}
func WithUserID(id int) UserAttrFunc {
return func(u *User) {
u.Id=id
}
}
func WithUserName(name string) UserAttrFunc {
return func(u *User) {
u.Name=name
}
}
type User struct {
Id int
Name string
Sex byte
}
// 有选择性的对ID 进行赋值
func NewUser(fs ...UserAttrFunc) *User {
u:= new(User)
UserAttrFuncs(fs).apply(u)
return u
}
func main() {
u:=NewUser(
WithUserName("shenyi"),
WithUserID(105),
)
fmt.Println(u)
}
复制代码
5. 简单工厂模式
package main
import "fmt"
type UserType int
type User interface {
GetRole() string
}
type Member struct {}
func(this *Member) GetRole() string {
return "会员用户"
}
type Admin struct {}
func(this *Admin) GetRole() string {
return "后台管理用户"
}
// 枚举类型
const (
Mem UserType = iota
Adm
)
func CreateUser(t UserType) User{
switch t {
case Mem:
return new(Member)
case Adm:
return new(Admin)
default:
return new(Member)
}
}
func main() {
fmt.Println(CreateUser(Adm).GetRole())
}
复制代码
6. 抽象工厂模式
- 抽象工厂模式,主要也是在多态情况下的一种高维护性和扩展性的设计模式,符合高层代码不应以来具体模块的实现而应依赖于抽象这么一个设计思想;
package main
import "fmt"
type User interface {
GetRole() string
}
type Member struct {}
func(this *Member) GetRole() string {
return "会员用户"
}
type Admin struct {}
func(this *Admin) GetRole() string {
return "后台管理用户"
}
const (
Mem=iota
Adm
)
func CreateUser(t int) User{
switch t {
case Mem:
return new(Member)
case Adm:
return new(Admin)
default:
return new(Member)
}
}
type AbstractFactory interface {
CreateUser() User
}
type MemberFactory struct {}
func(this *MemberFactory) CreateUser() User{
return &Member{}
}
type AdminFactory struct {}
func(this *AdminFactory) CreateUser() User{
return &Admin{}
}
func main() {
var fact AbstractFactory=new(AdminFactory)
fmt.Println(fact.CreateUser().GetRole())
}
复制代码
7. 装饰器模式
- 装饰器是体现AOP思想的一种设计模式;在无需改动原有方法的前提下添加新功能;
package main
import "net/http"
func CheckLogin(f http.HandlerFunc) http.HandlerFunc{
return func(writer http.ResponseWriter, request *http.Request) {
if request.URL.Query().Get("token")==""{
writer.Write([]byte("token error"))
}else{
f(writer,request)
}
}
}
func index(writer http.ResponseWriter, request *http.Request) {
writer.Write([]byte("index"))
}
func main() {
http.HandleFunc("/",CheckLogin(index) )
http.ListenAndServe(":8080",nil)
}
复制代码
8. 简易前缀树
- 多用于在路由框架,进行路由匹配
package main
import "fmt"
type Node struct {
isend bool //是否最后一个
Children map[string]*Node //这一步 用map就省的遍历了
}
func NewNode() *Node {
return &Node{Children:make(map[string]*Node)}
}
type Trie struct {
root *Node
}
func NewTrie() *Trie {
return &Trie{root:NewNode()}
}
func(this *Trie) Insert(str string ){
// 第一个肯定是空节点
current:=this.root
for _,item:=range ([]rune)(str){
if _,ok:=current.Children[string(item)];!ok{
current.Children[string(item)]=NewNode()
}
current=current.Children[string(item)]
}
current.isend=true //最后一个
}
func(this *Trie) Search(str string ) bool{
current:=this.root
for _,item:=range ([]rune)(str){
if _,ok:=current.Children[string(item)];!ok{
return false
}
current=current.Children[string(item)]
}
return current.isend //最后一个
}
func test() {
strs:=[]string{"go","gin","golang","goapp","guest"}
tree:=NewTrie()
for _,s:=range strs{
tree.Insert(s)
}
// 最终一个都匹配不到
strs=append(strs,"gi","gogo","gia")
for _,s:=range strs{
fmt.Println(tree.Search(s))
}
}
func main() {
test()
}
复制代码
9. 行读取文件或字符串
package main
import (
"bufio"
"bytes"
"fmt"
"log"
"strings"
)
func dropCR(data []byte) []byte {
if len(data) > 0 && data[len(data)-1] == ':' {
return data[0 : len(data)-1]
}
return data
}
func split(data []byte, atEOF bool) (advance int, token []byte, err error) {
if atEOF && len(data) == 0 {
return 0, nil, nil
}
if i := bytes.IndexByte(data, ':'); i >= 0 {
// We have a full newline-terminated line.
return i + 1, dropCR(data[0:i]), nil
}
// If we're at EOF, we have a final, non-terminated line. Return it.
if atEOF {
return len(data), dropCR(data), nil
}
// Request more data.
return 0, nil, nil
}
func main() {
/*
Scanner 方法
NewScanner 创建 Scanner
Scanner.Split 设置处理函数
Scanner.Scan 获取当前token, 扫描下一token
Scanner.Bytes 将token以 []byte 的形式返回
Scanner.Text 将token以 string 的形式返回
Scanner.Err 获取处理方法返回的错误
*/
reader := strings.NewReader("aaa:bbb:ccc:ddd:eee:fff:ggg")
scanner := bufio.NewScanner(reader)
/*
ScanBytes 将token处理为单一字节
ScanRunes 将token处理为utf-8编码的unicode码
ScanWords 以空格分隔
tokenScanLines 以换行符分分割token
*/
// 替换原有默认以'\n'的形式切割,上面两端代码是模仿源码的分割函数
scanner.Split(split)
count := 0
for scanner.Scan() {
log.Println(scanner.Text())
count++
}
fmt.Println("一共有", count, "行")
}
复制代码
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END