improve process communication feature for gproc; add more slice converting functions for gconv

This commit is contained in:
John
2019-12-11 21:22:41 +08:00
parent 81d4082b6a
commit 87295ef1fe
30 changed files with 1664 additions and 791 deletions

View File

@ -1,6 +1,3 @@
// 多进程通信示例,
// 子进程每个1秒向父进程发送当前时间
// 父进程监听进程消息,收到后打印到终端。
package main
import (

View File

@ -5,9 +5,8 @@ import (
"github.com/gogf/gf/os/gproc"
)
// 使用gproc kill指定其他进程(清确保运行该程序的用户有足够权限)
func main() {
pid := 14746
pid := 32556
m := gproc.NewManager()
m.AddProcess(pid)
err := m.KillAll()

View File

@ -0,0 +1,12 @@
package main
import (
"fmt"
"github.com/gogf/gf/os/gproc"
)
func main() {
fmt.Println(gproc.Pid())
err := gproc.ShellRun("sleep 99999s")
fmt.Println(err)
}

View File

@ -1,3 +0,0 @@
[database]
debug = true
link = "mysql:root:12345678@tcp(127.0.0.1:3306)/test?parseTime=true&loc=Local"

View File

@ -1,42 +0,0 @@
package main
import (
"fmt"
)
func main() {
fmt.Println("")
// 前景 背景 颜色
// ---------------------------------------
// 30 40 黑色
// 31 41 红色
// 32 42 绿色
// 33 43 黄色
// 34 44 蓝色
// 35 45 紫红色
// 36 46 青蓝色
// 37 47 白色
//
// 代码 意义
// -------------------------
// 0 终端默认设置
// 1 高亮显示
// 4 使用下划线
// 5 闪烁
// 7 反白显示
// 8 不可见
// 背景色彩 = 40-47
for b := 40; b <= 47; b++ {
// 前景色彩 = 30-37
for f := 30; f <= 37; f++ {
// 显示方式 = 0,1,4,5,7,8
for _, d := range []int{0, 1, 4, 5, 7, 8} {
fmt.Printf(" %c[%d;%d;%dm%s(f=%d,b=%d,d=%d)%c[0m ", 0x1B, d, b, f, "", f, b, d, 0x1B)
}
fmt.Println("")
}
fmt.Println("")
}
}

View File

@ -1,18 +1,69 @@
package main
import (
"github.com/gogf/gf/frame/g"
"github.com/gogf/gf/net/ghttp"
"fmt"
"github.com/gogf/gf/encoding/gjson"
"github.com/gogf/gf/os/glog"
)
func main() {
s := g.Server()
s.Group("/api.v2", func(group *ghttp.RouterGroup) {
group.ALL("/test", func(r *ghttp.Request) {
r.Response.Write(r.GetRequest("nickname"))
})
})
s.SetPort(8199)
s.Run()
type Detail struct {
Mall_coupon_id int64 `json:"mall_coupon_id"` //店铺优惠券id
Mall_coupon_discount_pct int `json:"mall_coupon_discount_pct"` //店铺折扣
Mall_coupon_min_order_amount int `json:"mall_coupon_min_order_amount"` //最小使用金额
Mall_coupon_max_discount_amount int `json:"mall_coupon_max_discount_amount"` //最大使用金额
Mall_coupon_total_quantity int64 `json:"mall_coupon_total_quantity"` //店铺券总量
Mall_coupon_remain_quantity int64 `json:"mall_coupon_remain_quantity"` //店铺券余量
Mall_coupon_start_time int64 `json:"mall_coupon_start_time"` //店铺券使用开始时间
Mall_coupon_end_time int64 `json:"mall_coupon_end_time"` //店铺券使用结束时间
Goods_id int64 `json:"goods_id"` //参与多多进宝的商品ID
Goods_name string `json:"goods_name"` //参与多多进宝的商品标题
Goods_desc string `json:"goods_desc"` //参与多多进宝的商品描述
Goods_image_url string `json:"goods_image_url"` //多多进宝商品主图
Goods_gallery_urls []string `json:"goods_gallery_urls"` //商品轮播图
Min_group_price int64 `json:"min_group_price"` //最低价sku的拼团价单位为分
Min_normal_price int64 `json:"min_normal_price"` //最低价sku的单买价单位为分
Mall_name string `json:"mall_name"` //店铺名称
Opt_id int64 `json:"opt_id"` //商品标签ID使用pdd.goods.opt.get接口获取
Opt_name string `json:"opt_name"` //商品标签名称
Opt_ids []int `json:"opt_ids"` //商品标签ID
Cat_ids []int `json:"cat_ids"` //商品一~四级类目ID列表
Coupon_min_order_amount int64 `json:"coupon_min_order_amount"` //优惠券门槛金额,单位为分
Coupon_discount int64 `json:"coupon_discount"` //优惠券面额,单位为分
Coupon_total_quantity int64 `json:"coupon_total_quantity"` //优惠券总数量
Coupon_remain_quantity int64 `json:"coupon_remain_quantity"` //优惠券剩余数量
Coupon_start_time int64 `json:"coupon_start_time"` //优惠券生效时间UNIX时间戳
Coupon_end_time int64 `json:"coupon_end_time"` //优惠券失效时间UNIX时间戳
Promotion_rate int64 `json:"promotion_rate"` //佣金比例,千分比
Goods_eval_count int64 `json:"goods_eval_count"` //商品评价数
Cat_id int64 `json:"cat_id"` //商品类目ID使用pdd.goods.cats.get接口获取
Sales_tip string `json:"sales_tip"` //已售卖件数
Mall_id int64 `json:"mall_id"` //商家id
Service_tags []int64 `json:"service_tags"` // 服务标签: 4-送货入户并安装,5-送货入户,6-电子发票,9-坏果包赔 ...
Clt_cpn_batch_sn string `json:"clt_cpn_batch_sn"` //店铺收藏券id
Clt_cpn_start_time int64 `json:"clt_cpn_start_time"` //店铺收藏券起始时间
Clt_cpn_end_time int64 `json:"clt_cpn_end_time"` //店铺收藏券截止时间
Clt_cpn_quantity int64 `json:"clt_cpn_quantity"` //店铺收藏券总量
Clt_cpn_remain_quantity int64 `json:"clt_cpn_remain_quantity"` //店铺收藏券剩余量
Clt_cpn_discount int64 `json:"clt_cpn_discount"` //店铺收藏券面额,单位为分
Clt_cpn_min_amt int64 `json:"clt_cpn_min_amt"` //店铺收藏券使用门槛价格,单位为分
Desc_txt string `json:"desc_txt"` //描述分
Serv_txt string `json:"serv_txt"` //服务分
Lgst_txt string `json:"lgst_txt"` //物流分
Plan_type int `json:"plan_type"` //推广计划类型
Zs_duo_id int64 `json:"zs_duo_id"` //招商团长id
Only_scene_auth int `json:"only_scene_auth"` //快手专享
}
s := `{"goods_detail_response":{"goods_details":[{"category_name":"百货","clt_cpn_end_time":null,"clt_cpn_min_amt":null,"coupon_remain_quantity":7000,"clt_cpn_remain_quantity":null,"promotion_rate":110,"coupon_id":3248825612,"service_tags":[24,13],"mall_id":983152922,"mall_name":"唯美之恋麻雀专卖店","mall_coupon_end_time":0,"clt_cpn_batch_sn":null,"lgst_txt":"高","goods_name":"【40卷32卷12卷】家用实惠卫生纸无芯卷纸批发纸巾厕纸卷筒纸手纸","clt_cpn_discount":null,"goods_id":9133961778,"goods_gallery_urls":["https://t00img.yangkeduo.com/goods/images/2019-08-18/e05846e8-f317-47bf-987d-5ccc0864e60d.jpg","https://t00img.yangkeduo.com/goods/images/2019-12-06/91756ca8-f001-4394-87d3-e7a67dc81d5a.jpg","https://t00img.yangkeduo.com/goods/images/2019-12-07/14c8abe5-cc27-4265-a683-7e2b089bb82e.jpg","https://t00img.yangkeduo.com/goods/images/2019-08-18/c4d338c0-1922-463f-bfcd-accd02018e44.jpg","https://t00img.yangkeduo.com/goods/images/2019-08-18/2b7f67f8-7738-4462-8f27-243594401ecd.jpg","https://t00img.yangkeduo.com/goods/images/2019-08-18/9b9bf86c-a3a7-4de1-9169-8b25c756ed01.jpg","https://t00img.yangkeduo.com/goods/images/2019-12-01/e373de68-c8a4-4752-adbc-d26b1040f8b7.jpg","https://t00img.yangkeduo.com/goods/images/2019-11-25/e622ef70-d917-4606-86af-a238db8c2fce.jpg","https://t00img.yangkeduo.com/goods/images/2019-11-25/9dd92cdd-1a07-4261-9584-cfafb0ddd421.jpg","https://t00img.yangkeduo.com/goods/images/2019-12-03/f7088db8-02f9-412b-a96c-5b452f41d9e3.jpg"],"goods_desc":"本产品原材料精选原生木浆制造,先进喷浆制造工艺,纸质更柔软细腻,没有纸屑,更有韧劲。嘉禾纸业建厂15年,两大自主品牌纸语和唯美之恋,年产能两万万余吨,拥有先进的造纸设备,采用巴西进口制浆制作制造而成,纸质柔软细腻,吸水性强,致力于打造国内孕婴卫生纸首选品牌,深受广大消费者好评。","opt_name":"百货","opt_ids":[17665,10116,10696,330,12619,12,11212,8590,10702,8591,15,13903,8592,17680,12691,22102,13911,12696,22105,21915,223,292,12581,13926,360,10730,12586,20527,11187,8569,12729,17657,8570,8571,10110,10111],"goods_image_url":"https://t00img.yangkeduo.com/goods/images/2019-08-18/e05846e8-f317-47bf-987d-5ccc0864e60d.jpg","has_mall_coupon":false,"min_group_price":720,"coupon_start_time":1575820800,"coupon_discount":200,"coupon_end_time":1575993599,"zs_duo_id":0,"mall_coupon_remain_quantity":0,"plan_type":2,"clt_cpn_quantity":null,"crt_rf_ordr_rto1m":0.03807085638781072,"cat_ids":[17285,17297,17402],"coupon_min_order_amount":200,"category_id":17657,"mall_coupon_discount_pct":0,"cat_id":null,"coupon_total_quantity":12000,"mall_coupon_min_order_amount":0,"merchant_type":4,"clt_cpn_start_time":null,"sales_tip":"4.2万","plan_type_all":4,"only_scene_auth":true,"mall_coupon_id":0,"desc_txt":"高","goods_thumbnail_url":"https://t00img.yangkeduo.com/goods/images/2019-11-20/0b0d078822c6e777ed1eb4ac2cdc930a.jpeg","opt_id":17657,"search_id":null,"min_normal_price":1190,"has_coupon":true,"mall_coupon_start_time":0,"serv_txt":"高","mall_rate":110,"mall_coupon_total_quantity":0,"create_at":null,"mall_coupon_max_discount_amount":0,"mall_cps":1}],"request_id":"15758638812810680"}}`
if j, err := gjson.DecodeToJson([]byte(s)); err != nil {
glog.Error(err)
} else {
inter := j.GetInterfaces("goods_detail_response.goods_details.0")
fmt.Println("接口:", inter)
detail := Detail{}
err := j.GetStruct("goods_detail_response.goods_details.0", &detail)
fmt.Println("结构体:", err, detail)
}
}

View File

@ -1,17 +1,17 @@
package main
import (
"github.com/gogf/gf/os/gproc"
"log"
"fmt"
"github.com/gogf/gf/frame/g"
"github.com/gogf/gf/util/gconv"
)
func main() {
process := gproc.NewProcessCmd("go run test.go")
if pid, err := process.Start(); err != nil {
log.Print("Build failed:", err)
return
} else {
log.Printf("Build running: pid: %d", pid)
type User struct {
Scores []int64
}
user := new(User)
err := gconv.Struct(g.Map{"scores": []interface{}{1, 2, 3}}, user)
fmt.Println(err)
fmt.Println(user)
}

View File

@ -1,22 +0,0 @@
package main
import (
"github.com/gogf/gf/frame/g"
"github.com/gogf/gf/os/glog"
)
func main() {
g.TryCatch(func() {
glog.Println("hello")
g.Throw("exception")
glog.Println("world")
})
g.TryCatch(func() {
glog.Println("hello")
g.Throw("exception")
glog.Println("world")
}, func(exception interface{}) {
glog.Error(exception)
})
}

View File

@ -74,6 +74,7 @@ type ServerConfig struct {
FormParsingMemory int64 // Other: Max memory in bytes which can be used for parsing multimedia form.
NameToUriType int // Other: Type for converting struct method name to URI when registering routes.
DumpRouterMap bool // Other: Whether automatically dump router map when server starts.
Graceful bool // Other: Enable graceful reload feature for all servers of the process.
}
// defaultServerConfig is the default configuration object for server.
@ -108,6 +109,7 @@ var defaultServerConfig = ServerConfig{
DumpRouterMap: true,
FormParsingMemory: 100 * 1024 * 1024, // 100MB
Rewrites: make(map[string]string),
Graceful: true,
}
// Config returns the default ServerConfig object.
@ -140,6 +142,7 @@ func (s *Server) SetConfig(c ServerConfig) error {
if c.TLSConfig == nil && c.HTTPSCertPath != "" {
s.EnableHTTPS(c.HTTPSCertPath, c.HTTPSKeyPath)
}
SetGraceful(c.Graceful)
return nil
}

View File

@ -161,13 +161,14 @@ func getPkgOption(option ...PkgOption) (*PkgOption, error) {
case 3:
pkgOption.MaxDataSize = 0xFFFFFF
case 4:
pkgOption.MaxDataSize = 0xFFFFFFFF
// math.MaxInt32 not math.MaxUint32
pkgOption.MaxDataSize = 0x7FFFFFFF
}
}
if pkgOption.MaxDataSize > 0xFFFFFFFF {
if pkgOption.MaxDataSize > 0x7FFFFFFF {
return nil, fmt.Errorf(
`package data size %d definition exceeds allowed max data size %d`,
pkgOption.MaxDataSize, 0xFFFFFFFF,
pkgOption.MaxDataSize, 0x7FFFFFFF,
)
}
return &pkgOption, nil

View File

@ -23,7 +23,7 @@ type PoolConn struct {
}
const (
gDEFAULT_POOL_EXPIRE = 30000 // (Millisecond) Default TTL for connection in the pool.
gDEFAULT_POOL_EXPIRE = 10000 // (Millisecond) Default TTL for connection in the pool.
gCONN_STATUS_UNKNOWN = 0 // Means it is unknown it's connective or not.
gCONN_STATUS_ACTIVE = 1 // Means it is now connective.
gCONN_STATUS_ERROR = 2 // Means it should be closed and removed from pool.
@ -36,27 +36,18 @@ var (
// NewPoolConn creates and returns a connection with pool feature.
func NewPoolConn(addr string, timeout ...time.Duration) (*PoolConn, error) {
var pool *gpool.Pool
if v := addressPoolMap.Get(addr); v == nil {
addressPoolMap.LockFunc(func(m map[string]interface{}) {
if v, ok := m[addr]; ok {
pool = v.(*gpool.Pool)
v := addressPoolMap.GetOrSetFuncLock(addr, func() interface{} {
var pool *gpool.Pool
pool = gpool.New(gDEFAULT_POOL_EXPIRE, func() (interface{}, error) {
if conn, err := NewConn(addr, timeout...); err == nil {
return &PoolConn{conn, pool, gCONN_STATUS_ACTIVE}, nil
} else {
pool = gpool.New(gDEFAULT_POOL_EXPIRE, func() (interface{}, error) {
if conn, err := NewConn(addr, timeout...); err == nil {
return &PoolConn{conn, pool, gCONN_STATUS_ACTIVE}, nil
} else {
return nil, err
}
})
m[addr] = pool
return nil, err
}
})
} else {
pool = v.(*gpool.Pool)
}
if v, err := pool.Get(); err == nil {
return pool
})
if v, err := v.(*gpool.Pool).Get(); err == nil {
return v.(*PoolConn), nil
} else {
return nil, err
@ -65,6 +56,9 @@ func NewPoolConn(addr string, timeout ...time.Duration) (*PoolConn, error) {
// Close puts back the connection to the pool if it's active,
// or closes the connection if it's not active.
//
// Note that, if <c> calls Close function closing itself, <c> should not
// be used again.
func (c *PoolConn) Close() error {
if c.pool != nil && c.status == gCONN_STATUS_ACTIVE {
c.status = gCONN_STATUS_UNKNOWN
@ -78,8 +72,8 @@ func (c *PoolConn) Close() error {
// Send writes data to the connection. It retrieves a new connection from its pool if it fails
// writing data.
func (c *PoolConn) Send(data []byte, retry ...Retry) error {
var err error
if err = c.Conn.Send(data, retry...); err != nil && c.status == gCONN_STATUS_UNKNOWN {
err := c.Conn.Send(data, retry...)
if err != nil && c.status == gCONN_STATUS_UNKNOWN {
if v, e := c.pool.Get(); e == nil {
c.Conn = v.(*PoolConn).Conn
err = c.Send(data, retry...)

View File

@ -0,0 +1,21 @@
// Copyright 2017 gf Author(https://github.com/gogf/gf). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package gtcp_test
import (
"github.com/gogf/gf/container/garray"
)
var (
ports = garray.NewIntArray(true)
)
func init() {
for i := 9000; i <= 10000; i++ {
ports.Append(i)
}
}

View File

@ -8,7 +8,6 @@ package gtcp_test
import (
"fmt"
"github.com/gogf/gf/container/garray"
"github.com/gogf/gf/net/gtcp"
"github.com/gogf/gf/test/gtest"
"github.com/gogf/gf/util/gconv"
@ -16,16 +15,6 @@ import (
"time"
)
var (
ports = garray.NewIntArray(true)
)
func init() {
for i := 9000; i <= 10000; i++ {
ports.Append(i)
}
}
func Test_Package_Basic(t *testing.T) {
p := ports.PopRand()
s := gtcp.NewServer(fmt.Sprintf(`:%d`, p), func(conn *gtcp.Conn) {

View File

@ -0,0 +1,172 @@
// Copyright 2017 gf Author(https://github.com/gogf/gf). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package gtcp_test
import (
"fmt"
"github.com/gogf/gf/net/gtcp"
"github.com/gogf/gf/test/gtest"
"github.com/gogf/gf/util/gconv"
"testing"
"time"
)
func Test_Pool_Package_Basic(t *testing.T) {
p := ports.PopRand()
s := gtcp.NewServer(fmt.Sprintf(`:%d`, p), func(conn *gtcp.Conn) {
defer conn.Close()
for {
data, err := conn.RecvPkg()
if err != nil {
break
}
conn.SendPkg(data)
}
})
go s.Run()
defer s.Close()
time.Sleep(100 * time.Millisecond)
// SendPkg
gtest.Case(t, func() {
conn, err := gtcp.NewPoolConn(fmt.Sprintf("127.0.0.1:%d", p))
gtest.Assert(err, nil)
defer conn.Close()
for i := 0; i < 100; i++ {
err := conn.SendPkg([]byte(gconv.String(i)))
gtest.Assert(err, nil)
}
for i := 0; i < 100; i++ {
err := conn.SendPkgWithTimeout([]byte(gconv.String(i)), time.Second)
gtest.Assert(err, nil)
}
})
// SendPkg with big data - failure.
gtest.Case(t, func() {
conn, err := gtcp.NewPoolConn(fmt.Sprintf("127.0.0.1:%d", p))
gtest.Assert(err, nil)
defer conn.Close()
data := make([]byte, 65536)
err = conn.SendPkg(data)
gtest.AssertNE(err, nil)
})
// SendRecvPkg
gtest.Case(t, func() {
conn, err := gtcp.NewPoolConn(fmt.Sprintf("127.0.0.1:%d", p))
gtest.Assert(err, nil)
defer conn.Close()
for i := 100; i < 200; i++ {
data := []byte(gconv.String(i))
result, err := conn.SendRecvPkg(data)
gtest.Assert(err, nil)
gtest.Assert(result, data)
}
for i := 100; i < 200; i++ {
data := []byte(gconv.String(i))
result, err := conn.SendRecvPkgWithTimeout(data, time.Second)
gtest.Assert(err, nil)
gtest.Assert(result, data)
}
})
// SendRecvPkg with big data - failure.
gtest.Case(t, func() {
conn, err := gtcp.NewPoolConn(fmt.Sprintf("127.0.0.1:%d", p))
gtest.Assert(err, nil)
defer conn.Close()
data := make([]byte, 65536)
result, err := conn.SendRecvPkg(data)
gtest.AssertNE(err, nil)
gtest.Assert(result, nil)
})
// SendRecvPkg with big data - success.
gtest.Case(t, func() {
conn, err := gtcp.NewPoolConn(fmt.Sprintf("127.0.0.1:%d", p))
gtest.Assert(err, nil)
defer conn.Close()
data := make([]byte, 65500)
data[100] = byte(65)
data[65400] = byte(85)
result, err := conn.SendRecvPkg(data)
gtest.Assert(err, nil)
gtest.Assert(result, data)
})
}
func Test_Pool_Package_Timeout(t *testing.T) {
p := ports.PopRand()
s := gtcp.NewServer(fmt.Sprintf(`:%d`, p), func(conn *gtcp.Conn) {
defer conn.Close()
for {
data, err := conn.RecvPkg()
if err != nil {
break
}
time.Sleep(time.Second)
gtest.Assert(conn.SendPkg(data), nil)
}
})
go s.Run()
defer s.Close()
time.Sleep(100 * time.Millisecond)
gtest.Case(t, func() {
conn, err := gtcp.NewPoolConn(fmt.Sprintf("127.0.0.1:%d", p))
gtest.Assert(err, nil)
defer conn.Close()
data := []byte("10000")
result, err := conn.SendRecvPkgWithTimeout(data, time.Millisecond*500)
gtest.AssertNE(err, nil)
gtest.Assert(result, nil)
})
gtest.Case(t, func() {
conn, err := gtcp.NewPoolConn(fmt.Sprintf("127.0.0.1:%d", p))
gtest.Assert(err, nil)
defer conn.Close()
data := []byte("10000")
result, err := conn.SendRecvPkgWithTimeout(data, time.Second*2)
gtest.Assert(err, nil)
gtest.Assert(result, data)
})
}
func Test_Pool_Package_Option(t *testing.T) {
p := ports.PopRand()
s := gtcp.NewServer(fmt.Sprintf(`:%d`, p), func(conn *gtcp.Conn) {
defer conn.Close()
option := gtcp.PkgOption{HeaderSize: 1}
for {
data, err := conn.RecvPkg(option)
if err != nil {
break
}
gtest.Assert(conn.SendPkg(data, option), nil)
}
})
go s.Run()
defer s.Close()
time.Sleep(100 * time.Millisecond)
// SendRecvPkg with big data - failure.
gtest.Case(t, func() {
conn, err := gtcp.NewPoolConn(fmt.Sprintf("127.0.0.1:%d", p))
gtest.Assert(err, nil)
defer conn.Close()
data := make([]byte, 0xFF+1)
result, err := conn.SendRecvPkg(data, gtcp.PkgOption{HeaderSize: 1})
gtest.AssertNE(err, nil)
gtest.Assert(result, nil)
})
// SendRecvPkg with big data - success.
gtest.Case(t, func() {
conn, err := gtcp.NewPoolConn(fmt.Sprintf("127.0.0.1:%d", p))
gtest.Assert(err, nil)
defer conn.Close()
data := make([]byte, 0xFF)
data[100] = byte(65)
data[200] = byte(85)
result, err := conn.SendRecvPkg(data, gtcp.PkgOption{HeaderSize: 1})
gtest.Assert(err, nil)
gtest.Assert(result, data)
})
}

View File

@ -0,0 +1,65 @@
// Copyright 2017 gf Author(https://github.com/gogf/gf). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package gtcp_test
import (
"fmt"
"github.com/gogf/gf/net/gtcp"
"github.com/gogf/gf/test/gtest"
"testing"
"time"
)
func Test_Pool_Basic1(t *testing.T) {
p := ports.PopRand()
s := gtcp.NewServer(fmt.Sprintf(`:%d`, p), func(conn *gtcp.Conn) {
defer conn.Close()
for {
data, err := conn.RecvPkg()
if err != nil {
break
}
conn.SendPkg(data)
}
})
go s.Run()
defer s.Close()
time.Sleep(100 * time.Millisecond)
gtest.Case(t, func() {
conn, err := gtcp.NewPoolConn(fmt.Sprintf("127.0.0.1:%d", p))
gtest.Assert(err, nil)
defer conn.Close()
data := []byte("9999")
err = conn.SendPkg(data)
gtest.Assert(err, nil)
err = conn.SendPkgWithTimeout(data, time.Second)
gtest.Assert(err, nil)
})
}
func Test_Pool_Basic2(t *testing.T) {
p := ports.PopRand()
s := gtcp.NewServer(fmt.Sprintf(`:%d`, p), func(conn *gtcp.Conn) {
conn.Close()
})
go s.Run()
defer s.Close()
time.Sleep(100 * time.Millisecond)
gtest.Case(t, func() {
conn, err := gtcp.NewPoolConn(fmt.Sprintf("127.0.0.1:%d", p))
gtest.Assert(err, nil)
defer conn.Close()
data := []byte("9999")
err = conn.SendPkg(data)
gtest.Assert(err, nil)
err = conn.SendPkgWithTimeout(data, time.Second)
gtest.Assert(err, nil)
_, err = conn.SendRecv(data, -1)
gtest.AssertNE(err, nil)
})
}

View File

@ -36,8 +36,16 @@ var (
// The absolute file path for main package.
// It can be only checked and set once.
mainPkgPath = gtype.NewString()
// Temporary directory of system.
tempDir = "/tmp"
)
func init() {
if !Exists(tempDir) {
tempDir = os.TempDir()
}
}
// Mkdir creates directories recursively with given <path>.
// The parameter <path> is suggested to be absolute path.
func Mkdir(path string) error {
@ -511,5 +519,5 @@ func homeWindows() (string, error) {
// See os.TempDir().
func TempDir() string {
return os.TempDir()
return tempDir
}

View File

@ -9,6 +9,7 @@ package gproc
import (
"bytes"
"github.com/gogf/gf/text/gstr"
"io"
"os"
"runtime"
@ -21,15 +22,14 @@ import (
const (
gPROC_ENV_KEY_PPID_KEY = "GPROC_PPID"
gPROC_TEMP_DIR_ENV_KEY = "GPROC_TEMP_DIR"
)
var (
// 进程开始执行时间
// processStartTime is the start time of current process.
processStartTime = time.Now()
)
// 获取当前进程ID
// Pid returns the pid of current process.
func Pid() int {
return os.Getpid()
}
@ -39,7 +39,6 @@ func PPid() int {
if !IsChild() {
return Pid()
}
// gPROC_ENV_KEY_PPID_KEY为gproc包自定义的父进程
ppidValue := os.Getenv(gPROC_ENV_KEY_PPID_KEY)
if ppidValue != "" && ppidValue != "0" {
return gconv.Int(ppidValue)
@ -114,11 +113,11 @@ func checkEnvKey(env []string, key string) bool {
func getShell() string {
switch runtime.GOOS {
case "windows":
return searchBinFromEnvPath("cmd.exe")
return SearchBinary("cmd.exe")
default:
path := searchBinFromEnvPath("bash")
path := SearchBinary("bash")
if path == "" {
path = searchBinFromEnvPath("sh")
path = SearchBinary("sh")
}
return path
}
@ -135,24 +134,25 @@ func getShellOption() string {
}
// 从环境变量PATH中搜索可执行文件
func searchBinFromEnvPath(file string) string {
// 如果是绝对路径,或者相对路径下存在,那么直接返回
func SearchBinary(file string) string {
// Check if it's absolute path of exists at current working directory.
if gfile.Exists(file) {
return file
}
array := ([]string)(nil)
switch runtime.GOOS {
case "windows":
array = strings.Split(os.Getenv("Path"), ";")
array = gstr.SplitAndTrim(os.Getenv("Path"), ";")
if gfile.Ext(file) != ".exe" {
file += ".exe"
}
default:
array = strings.Split(os.Getenv("PATH"), ":")
array = gstr.SplitAndTrim(os.Getenv("PATH"), ":")
}
if len(array) > 0 {
path := ""
for _, v := range array {
path := v + gfile.Separator + file
path = v + gfile.Separator + file
if gfile.Exists(path) {
return path
}

View File

@ -3,42 +3,81 @@
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
// "不要通过共享内存来通信,而应该通过通信来共享内存"
package gproc
import (
"os"
"errors"
"fmt"
"github.com/gogf/gf/container/gmap"
"github.com/gogf/gf/net/gtcp"
"github.com/gogf/gf/os/gfcache"
"github.com/gogf/gf/os/gfile"
"github.com/gogf/gf/util/gconv"
)
// 进程通信数据结构
type Msg struct {
SendPid int `json:"spid"` // 发送进程ID
RecvPid int `json:"rpid"` // 接收进程ID
Group string `json:"group"` // 分组名称
Data []byte `json:"data"` // 原始数据
// MsgRequest is the request structure for process communication.
type MsgRequest struct {
SendPid int // Sender PID.
RecvPid int // Receiver PID.
Group string // Message group name.
Data []byte // Request data.
}
// 本地进程通信接收消息队列(按照分组进行构建的map键值为*gqueue.Queue对象)
var commReceiveQueues = gmap.NewStrAnyMap(true)
// (用于发送)已建立的PID对应的Conn通信对象键值为一个Pool防止并行使用同一个通信对象造成数据重叠
var commPidConnMap = gmap.NewIntAnyMap(true)
// 获取指定进程的通信文件地址
func getCommFilePath(pid int) string {
return getCommDirPath() + gfile.Separator + gconv.String(pid)
// MsgResponse is the response structure for process communication.
type MsgResponse struct {
Code int // 1: OK; Other: Error.
Message string // Response message.
Data []byte // Response data.
}
// 获取进程间通信目录地址
func getCommDirPath() string {
tempDir := os.Getenv(gPROC_TEMP_DIR_ENV_KEY)
if tempDir == "" {
tempDir = gfile.TempDir()
const (
gPROC_COMM_DEFAULT_GRUOP_NAME = "" // Default group name.
gPROC_DEFAULT_TCP_PORT = 10000 // Starting port number for receiver listening.
gPROC_MSG_QUEUE_MAX_LENGTH = 10000 // Max size for each message queue of the group.
)
var (
// commReceiveQueues is the group name to queue map for storing received data.
// The value of the map is type of *gqueue.Queue.
commReceiveQueues = gmap.NewStrAnyMap(true)
// commPidFolderPath specifies the folder path storing pid to port mapping files.
commPidFolderPath = gfile.Join(gfile.TempDir(), "gproc")
)
func init() {
// Automatically create the storage folder.
if !gfile.Exists(commPidFolderPath) {
err := gfile.Mkdir(commPidFolderPath)
if err != nil {
panic(fmt.Errorf(`create gproc folder failed: %v`, err))
}
}
return tempDir + gfile.Separator + "gproc"
}
// getConnByPid creates and returns a TCP connection for specified pid.
func getConnByPid(pid int) (*gtcp.Conn, error) {
port := getPortByPid(pid)
if port > 0 {
if conn, err := gtcp.NewConn(fmt.Sprintf("127.0.0.1:%d", port)); err == nil {
return conn, nil
} else {
return nil, err
}
}
return nil, errors.New(fmt.Sprintf("could not find port for pid: %d", pid))
}
// getPortByPid returns the listening port for specified pid.
// It returns 0 if no port found for the specified pid.
func getPortByPid(pid int) int {
path := getCommFilePath(pid)
content := gfcache.GetContents(path)
return gconv.Int(content)
}
// getCommFilePath returns the pid to port mapping file path for given pid.
func getCommFilePath(pid int) string {
return gfile.Join(commPidFolderPath, gconv.String(pid))
}

View File

@ -21,50 +21,39 @@ import (
"github.com/gogf/gf/util/gconv"
)
const (
gPROC_DEFAULT_TCP_PORT = 10000 // 默认开始监听的TCP端口号如果占用则递增
gPROC_MSG_QUEUE_MAX_LENGTH = 10000 // 进程消息队列最大长度(每个分组)
)
var (
// 是否已开启TCP端口监听服务
// tcpListened marks whether the receiving listening service started.
tcpListened = gtype.NewBool()
)
// 获取其他进程传递到当前进程的消息包,阻塞执行。
// 进程只有在执行该方法后才会打开请求端口,默认情况下不允许进程间通信。
func Receive(group ...string) *Msg {
// 一个进程只能开启一个监听goroutine
if !tcpListened.Val() && tcpListened.Set(true) == false {
go startTcpListening()
// Receive blocks and receives message from other process using local TCP listening.
// Note that, it only enables the TCP listening service when this function called.
func Receive(group ...string) *MsgRequest {
// Use atomic operations to guarantee only one receiver goroutine listening.
if tcpListened.Cas(false, true) {
go receiveTcpListening()
}
queue := (*gqueue.Queue)(nil)
groupName := gPROC_COMM_DEFAULT_GRUOP_NAME
var groupName string
if len(group) > 0 {
groupName = group[0]
}
if v := commReceiveQueues.Get(groupName); v == nil {
commReceiveQueues.LockFunc(func(m map[string]interface{}) {
if v, ok := m[groupName]; ok {
queue = v.(*gqueue.Queue)
} else {
queue = gqueue.New(gPROC_MSG_QUEUE_MAX_LENGTH)
m[groupName] = queue
}
})
} else {
queue = v.(*gqueue.Queue)
groupName = gPROC_COMM_DEFAULT_GRUOP_NAME
}
queue := commReceiveQueues.GetOrSetFuncLock(groupName, func() interface{} {
return gqueue.New(gPROC_MSG_QUEUE_MAX_LENGTH)
}).(*gqueue.Queue)
// Blocking receiving.
if v := queue.Pop(); v != nil {
return v.(*Msg)
return v.(*MsgRequest)
}
return nil
}
// 创建本地进程TCP通信服务
func startTcpListening() {
// receiveTcpListening scans local for available port and starts listening.
func receiveTcpListening() {
var listen *net.TCPListener
// Scan the available port for listening.
for i := gPROC_DEFAULT_TCP_PORT; ; i++ {
addr, err := net.ResolveTCPAddr("tcp", fmt.Sprintf("127.0.0.1:%d", i))
if err != nil {
@ -74,57 +63,55 @@ func startTcpListening() {
if err != nil {
continue
}
// 将监听的端口保存到通信文件中(字符串类型存放)
// Save the port to the pid file.
if err := gfile.PutContents(getCommFilePath(Pid()), gconv.String(i)); err != nil {
glog.Error(err)
glog.Panic(err)
}
break
}
// Start listening.
for {
if conn, err := listen.Accept(); err != nil {
glog.Error(err)
} else if conn != nil {
go tcpServiceHandler(gtcp.NewConnByNetConn(conn))
go receiveTcpHandler(gtcp.NewConnByNetConn(conn))
}
}
}
// TCP数据通信处理回调函数
func tcpServiceHandler(conn *gtcp.Conn) {
option := gtcp.PkgOption{
Retry: gtcp.Retry{
Count: 3,
Interval: 10,
},
}
// receiveTcpHandler is the connection handler for receiving data.
func receiveTcpHandler(conn *gtcp.Conn) {
var result []byte
var response MsgResponse
for {
var result []byte
buffer, err := conn.RecvPkg(option)
buffer, err := conn.RecvPkg()
if len(buffer) > 0 {
msg := new(Msg)
msg := new(MsgRequest)
if err := json.Unmarshal(buffer, msg); err != nil {
glog.Error(err)
continue
}
if v := commReceiveQueues.Get(msg.Group); v == nil {
result = []byte(fmt.Sprintf("group [%s] does not exist", msg.Group))
break
response.Code = 0
response.Message = fmt.Sprintf("group [%s] does not exist", msg.Group)
} else {
result = []byte("ok")
if v := commReceiveQueues.Get(msg.Group); v != nil {
v.(*gqueue.Queue).Push(msg)
}
response.Code = 1
v.(*gqueue.Queue).Push(msg)
}
}
if err == nil {
if err := conn.SendPkg(result, option); err != nil {
result, err = json.Marshal(response)
if err != nil {
glog.Error(err)
}
if err := conn.SendPkg(result); err != nil {
glog.Error(err)
}
} else {
if err := conn.Close(); err != nil {
glog.Error(err)
}
return
break
}
}
}

View File

@ -7,28 +7,15 @@
package gproc
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io"
"time"
"github.com/gogf/gf/net/gtcp"
"github.com/gogf/gf/os/gfcache"
"github.com/gogf/gf/util/gconv"
"io"
)
const (
gPROC_COMM_FAILURE_RETRY_COUNT = 3 // 失败重试次数
gPROC_COMM_FAILURE_RETRY_TIMEOUT = 1000 // (毫秒)失败重试间隔
gPROC_COMM_SEND_TIMEOUT = 5000 // (毫秒)发送超时时间
gPROC_COMM_DEFAULT_GRUOP_NAME = "" // 默认分组名称
)
// 向指定gproc进程发送数据.
// Send sends data to specified process of given pid.
func Send(pid int, data []byte, group ...string) error {
msg := Msg{
msg := MsgRequest{
SendPid: Pid(),
RecvPid: pid,
Group: gPROC_COMM_DEFAULT_GRUOP_NAME,
@ -41,49 +28,27 @@ func Send(pid int, data []byte, group ...string) error {
if err != nil {
return err
}
var buf []byte
var conn *gtcp.PoolConn
// 循环获取连接TCP对象
for i := gPROC_COMM_FAILURE_RETRY_COUNT; i > 0; i-- {
if conn, err = getConnByPid(pid); err == nil {
break
}
time.Sleep(gPROC_COMM_FAILURE_RETRY_TIMEOUT * time.Millisecond)
}
if conn == nil {
var conn *gtcp.Conn
conn, err = getConnByPid(pid)
if err != nil {
return err
}
defer conn.Close()
// 执行数据发送
buf, err = conn.SendRecvPkgWithTimeout(msgBytes, gPROC_COMM_SEND_TIMEOUT*time.Millisecond)
if len(buf) > 0 {
if !bytes.EqualFold(buf, []byte("ok")) {
err = errors.New(string(buf))
// Do the sending.
var result []byte
result, err = conn.SendRecvPkg(msgBytes)
if len(result) > 0 {
response := new(MsgResponse)
err = json.Unmarshal(result, response)
if err == nil {
if response.Code != 1 {
err = errors.New(response.Message)
}
}
}
// EOF不算异常错误
// EOF is not really an error.
if err == io.EOF {
err = nil
}
return err
}
// 获取指定进程的TCP通信对象
func getConnByPid(pid int) (*gtcp.PoolConn, error) {
port := getPortByPid(pid)
if port > 0 {
if conn, err := gtcp.NewPoolConn(fmt.Sprintf("127.0.0.1:%d", port)); err == nil {
return conn, nil
} else {
return nil, err
}
}
return nil, errors.New(fmt.Sprintf("could not find port for pid: %d", pid))
}
// 获取指定进程监听的端口号
func getPortByPid(pid int) int {
path := getCommFilePath(pid)
content := gfcache.GetContents(path)
return gconv.Int(content)
}

View File

@ -4,7 +4,6 @@
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
// 进程管理.
package gproc
import (

View File

@ -25,15 +25,12 @@ type Process struct {
func NewProcess(path string, args []string, environment ...[]string) *Process {
var env []string
if len(environment) > 0 {
env = make([]string, 0)
for _, v := range environment[0] {
env = append(env, v)
}
env = make([]string, len(environment[0]))
copy(env, environment[0])
} else {
env = os.Environ()
}
env = append(env, fmt.Sprintf("%s=%s", gPROC_TEMP_DIR_ENV_KEY, os.TempDir()))
p := &Process{
process := &Process{
Manager: nil,
PPid: os.Getpid(),
Cmd: exec.Cmd{
@ -46,18 +43,16 @@ func NewProcess(path string, args []string, environment ...[]string) *Process {
ExtraFiles: make([]*os.File, 0),
},
}
// 当前工作目录
if d, err := os.Getwd(); err == nil {
p.Dir = d
}
process.Dir, _ = os.Getwd()
if len(args) > 0 {
// Exclude of current binary path.
start := 0
if strings.EqualFold(path, args[0]) {
start = 1
}
p.Args = append(p.Args, args[start:]...)
process.Args = append(process.Args, args[start:]...)
}
return p
return process
}
// NewProcessCmd creates and returns a process with given command and optional environment variable array.

View File

@ -49,7 +49,7 @@ var (
)
// Convert converts the variable <i> to the type <t>, the type <t> is specified by string.
// The unnecessary parameter <params> is used for additional parameter passing.
// The optional parameter <params> is used for additional parameter passing.
func Convert(i interface{}, t string, params ...interface{}) interface{} {
switch t {
case "int":
@ -84,6 +84,20 @@ func Convert(i interface{}, t string, params ...interface{}) interface{} {
return Bytes(i)
case "[]int":
return Ints(i)
case "[]int32":
return Int32s(i)
case "[]int64":
return Int64s(i)
case "[]uint":
return Uints(i)
case "[]uint32":
return Uint32s(i)
case "[]uint64":
return Uint64s(i)
case "[]float32":
return Float32s(i)
case "[]float64":
return Float64s(i)
case "[]string":
return Strings(i)
@ -188,8 +202,6 @@ func String(i interface{}) string {
return value
case []byte:
return string(value)
case []rune:
return string(value)
case *time.Time:
if value == nil {
return ""

View File

@ -10,35 +10,8 @@ import (
"errors"
"fmt"
"reflect"
"github.com/gogf/gf/internal/utilstr"
)
// SliceInt is alias of Ints.
func SliceInt(i interface{}) []int {
return Ints(i)
}
// SliceUint is alias of Uints.
func SliceUint(i interface{}) []uint {
return Uints(i)
}
// SliceStr is alias of Strings.
func SliceStr(i interface{}) []string {
return Strings(i)
}
// SliceAny is alias of Interfaces.
func SliceAny(i interface{}) []interface{} {
return Interfaces(i)
}
// SliceFloat is alias of Floats.
func SliceFloat(i interface{}) []float64 {
return Floats(i)
}
// SliceMap is alias of Maps.
func SliceMap(i interface{}) []map[string]interface{} {
return Maps(i)
@ -59,489 +32,6 @@ func SliceStructDeep(params interface{}, pointer interface{}, mapping ...map[str
return StructsDeep(params, pointer, mapping...)
}
// Ints converts <i> to []int.
func Ints(i interface{}) []int {
if i == nil {
return nil
}
if r, ok := i.([]int); ok {
return r
} else {
var array []int
switch value := i.(type) {
case []string:
array = make([]int, len(value))
for k, v := range value {
array[k] = Int(v)
}
case []int8:
array = make([]int, len(value))
for k, v := range value {
array[k] = int(v)
}
case []int16:
array = make([]int, len(value))
for k, v := range value {
array[k] = int(v)
}
case []int32:
array = make([]int, len(value))
for k, v := range value {
array[k] = int(v)
}
case []int64:
array = make([]int, len(value))
for k, v := range value {
array[k] = int(v)
}
case []uint:
array = make([]int, len(value))
for k, v := range value {
array[k] = int(v)
}
case []uint8:
array = make([]int, len(value))
for k, v := range value {
array[k] = int(v)
}
case []uint16:
array = make([]int, len(value))
for k, v := range value {
array[k] = int(v)
}
case []uint32:
array = make([]int, len(value))
for k, v := range value {
array[k] = int(v)
}
case []uint64:
array = make([]int, len(value))
for k, v := range value {
array[k] = int(v)
}
case []bool:
array = make([]int, len(value))
for k, v := range value {
if v {
array[k] = 1
} else {
array[k] = 0
}
}
case []float32:
array = make([]int, len(value))
for k, v := range value {
array[k] = Int(v)
}
case []float64:
array = make([]int, len(value))
for k, v := range value {
array[k] = Int(v)
}
case []interface{}:
array = make([]int, len(value))
for k, v := range value {
array[k] = Int(v)
}
case [][]byte:
array = make([]int, len(value))
for k, v := range value {
array[k] = Int(v)
}
default:
return []int{Int(i)}
}
return array
}
}
// Uints converts <i> to []uint.
func Uints(i interface{}) []uint {
if i == nil {
return nil
}
if r, ok := i.([]uint); ok {
return r
} else {
var array []uint
switch value := i.(type) {
case []string:
array = make([]uint, len(value))
for k, v := range value {
array[k] = Uint(v)
}
case []int8:
array = make([]uint, len(value))
for k, v := range value {
array[k] = uint(v)
}
case []int16:
array = make([]uint, len(value))
for k, v := range value {
array[k] = uint(v)
}
case []int32:
array = make([]uint, len(value))
for k, v := range value {
array[k] = uint(v)
}
case []int64:
array = make([]uint, len(value))
for k, v := range value {
array[k] = uint(v)
}
case []uint8:
array = make([]uint, len(value))
for k, v := range value {
array[k] = uint(v)
}
case []uint16:
array = make([]uint, len(value))
for k, v := range value {
array[k] = uint(v)
}
case []uint32:
array = make([]uint, len(value))
for k, v := range value {
array[k] = uint(v)
}
case []uint64:
array = make([]uint, len(value))
for k, v := range value {
array[k] = uint(v)
}
case []bool:
array = make([]uint, len(value))
for k, v := range value {
if v {
array[k] = 1
} else {
array[k] = 0
}
}
case []float32:
array = make([]uint, len(value))
for k, v := range value {
array[k] = Uint(v)
}
case []float64:
array = make([]uint, len(value))
for k, v := range value {
array[k] = Uint(v)
}
case []interface{}:
array = make([]uint, len(value))
for k, v := range value {
array[k] = Uint(v)
}
case [][]byte:
array = make([]uint, len(value))
for k, v := range value {
array[k] = Uint(v)
}
default:
return []uint{Uint(i)}
}
return array
}
}
// Strings converts <i> to []string.
func Strings(i interface{}) []string {
if i == nil {
return nil
}
if r, ok := i.([]string); ok {
return r
} else {
var array []string
switch value := i.(type) {
case []int:
array = make([]string, len(value))
for k, v := range value {
array[k] = String(v)
}
case []int8:
array = make([]string, len(value))
for k, v := range value {
array[k] = String(v)
}
case []int16:
array = make([]string, len(value))
for k, v := range value {
array[k] = String(v)
}
case []int32:
array = make([]string, len(value))
for k, v := range value {
array[k] = String(v)
}
case []int64:
array = make([]string, len(value))
for k, v := range value {
array[k] = String(v)
}
case []uint:
array = make([]string, len(value))
for k, v := range value {
array[k] = String(v)
}
case []uint8:
array = make([]string, len(value))
for k, v := range value {
array[k] = String(v)
}
case []uint16:
array = make([]string, len(value))
for k, v := range value {
array[k] = String(v)
}
case []uint32:
array = make([]string, len(value))
for k, v := range value {
array[k] = String(v)
}
case []uint64:
array = make([]string, len(value))
for k, v := range value {
array[k] = String(v)
}
case []bool:
array = make([]string, len(value))
for k, v := range value {
array[k] = String(v)
}
case []float32:
array = make([]string, len(value))
for k, v := range value {
array[k] = String(v)
}
case []float64:
array = make([]string, len(value))
for k, v := range value {
array[k] = String(v)
}
case []interface{}:
array = make([]string, len(value))
for k, v := range value {
array[k] = String(v)
}
case [][]byte:
array = make([]string, len(value))
for k, v := range value {
array[k] = String(v)
}
default:
return []string{String(i)}
}
return array
}
}
// Strings converts <i> to []float64.
func Floats(i interface{}) []float64 {
if i == nil {
return nil
}
if r, ok := i.([]float64); ok {
return r
} else {
var array []float64
switch value := i.(type) {
case []string:
array = make([]float64, len(value))
for k, v := range value {
array[k] = Float64(v)
}
case []int:
array = make([]float64, len(value))
for k, v := range value {
array[k] = Float64(v)
}
case []int8:
array = make([]float64, len(value))
for k, v := range value {
array[k] = Float64(v)
}
case []int16:
array = make([]float64, len(value))
for k, v := range value {
array[k] = Float64(v)
}
case []int32:
array = make([]float64, len(value))
for k, v := range value {
array[k] = Float64(v)
}
case []int64:
array = make([]float64, len(value))
for k, v := range value {
array[k] = Float64(v)
}
case []uint:
for _, v := range value {
array = append(array, Float64(v))
}
case []uint8:
array = make([]float64, len(value))
for k, v := range value {
array[k] = Float64(v)
}
case []uint16:
array = make([]float64, len(value))
for k, v := range value {
array[k] = Float64(v)
}
case []uint32:
array = make([]float64, len(value))
for k, v := range value {
array[k] = Float64(v)
}
case []uint64:
array = make([]float64, len(value))
for k, v := range value {
array[k] = Float64(v)
}
case []bool:
array = make([]float64, len(value))
for k, v := range value {
array[k] = Float64(v)
}
case []float32:
array = make([]float64, len(value))
for k, v := range value {
array[k] = Float64(v)
}
case []interface{}:
array = make([]float64, len(value))
for k, v := range value {
array[k] = Float64(v)
}
default:
return []float64{Float64(i)}
}
return array
}
}
// Type assert api for Interfaces.
type apiInterfaces interface {
Interfaces() []interface{}
}
// Interfaces converts <i> to []interface{}.
func Interfaces(i interface{}) []interface{} {
if i == nil {
return nil
}
if r, ok := i.([]interface{}); ok {
return r
} else if r, ok := i.(apiInterfaces); ok {
return r.Interfaces()
} else {
var array []interface{}
switch value := i.(type) {
case []string:
array = make([]interface{}, len(value))
for k, v := range value {
array[k] = v
}
case []int:
array = make([]interface{}, len(value))
for k, v := range value {
array[k] = v
}
case []int8:
array = make([]interface{}, len(value))
for k, v := range value {
array[k] = v
}
case []int16:
array = make([]interface{}, len(value))
for k, v := range value {
array[k] = v
}
case []int32:
array = make([]interface{}, len(value))
for k, v := range value {
array[k] = v
}
case []int64:
array = make([]interface{}, len(value))
for k, v := range value {
array[k] = v
}
case []uint:
array = make([]interface{}, len(value))
for k, v := range value {
array[k] = v
}
case []uint8:
array = make([]interface{}, len(value))
for k, v := range value {
array[k] = v
}
case []uint16:
array = make([]interface{}, len(value))
for k, v := range value {
array[k] = v
}
case []uint32:
for _, v := range value {
array = append(array, v)
}
case []uint64:
array = make([]interface{}, len(value))
for k, v := range value {
array[k] = v
}
case []bool:
array = make([]interface{}, len(value))
for k, v := range value {
array[k] = v
}
case []float32:
array = make([]interface{}, len(value))
for k, v := range value {
array[k] = v
}
case []float64:
array = make([]interface{}, len(value))
for k, v := range value {
array[k] = v
}
default:
// Finally we use reflection.
rv := reflect.ValueOf(i)
kind := rv.Kind()
for kind == reflect.Ptr {
rv = rv.Elem()
kind = rv.Kind()
}
switch kind {
case reflect.Slice, reflect.Array:
array = make([]interface{}, rv.Len())
for i := 0; i < rv.Len(); i++ {
array[i] = rv.Index(i).Interface()
}
case reflect.Struct:
rt := rv.Type()
array = make([]interface{}, 0)
for i := 0; i < rv.NumField(); i++ {
// Only public attributes.
if !utilstr.IsLetterUpper(rt.Field(i).Name[0]) {
continue
}
array = append(array, rv.Field(i).Interface())
}
default:
return []interface{}{i}
}
}
return array
}
}
// Maps converts <i> to []map[string]interface{}.
func Maps(value interface{}, tags ...string) []map[string]interface{} {
if value == nil {

View File

@ -0,0 +1,135 @@
// Copyright 2019 gf Author(https://github.com/gogf/gf). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package gconv
import (
"github.com/gogf/gf/internal/utilstr"
"reflect"
)
// SliceAny is alias of Interfaces.
func SliceAny(i interface{}) []interface{} {
return Interfaces(i)
}
// Type assert api for Interfaces.
type apiInterfaces interface {
Interfaces() []interface{}
}
// Interfaces converts <i> to []interface{}.
func Interfaces(i interface{}) []interface{} {
if i == nil {
return nil
}
if r, ok := i.([]interface{}); ok {
return r
} else if r, ok := i.(apiInterfaces); ok {
return r.Interfaces()
} else {
var array []interface{}
switch value := i.(type) {
case []string:
array = make([]interface{}, len(value))
for k, v := range value {
array[k] = v
}
case []int:
array = make([]interface{}, len(value))
for k, v := range value {
array[k] = v
}
case []int8:
array = make([]interface{}, len(value))
for k, v := range value {
array[k] = v
}
case []int16:
array = make([]interface{}, len(value))
for k, v := range value {
array[k] = v
}
case []int32:
array = make([]interface{}, len(value))
for k, v := range value {
array[k] = v
}
case []int64:
array = make([]interface{}, len(value))
for k, v := range value {
array[k] = v
}
case []uint:
array = make([]interface{}, len(value))
for k, v := range value {
array[k] = v
}
case []uint8:
array = make([]interface{}, len(value))
for k, v := range value {
array[k] = v
}
case []uint16:
array = make([]interface{}, len(value))
for k, v := range value {
array[k] = v
}
case []uint32:
for _, v := range value {
array = append(array, v)
}
case []uint64:
array = make([]interface{}, len(value))
for k, v := range value {
array[k] = v
}
case []bool:
array = make([]interface{}, len(value))
for k, v := range value {
array[k] = v
}
case []float32:
array = make([]interface{}, len(value))
for k, v := range value {
array[k] = v
}
case []float64:
array = make([]interface{}, len(value))
for k, v := range value {
array[k] = v
}
default:
// Finally we use reflection.
rv := reflect.ValueOf(i)
kind := rv.Kind()
for kind == reflect.Ptr {
rv = rv.Elem()
kind = rv.Kind()
}
switch kind {
case reflect.Slice, reflect.Array:
array = make([]interface{}, rv.Len())
for i := 0; i < rv.Len(); i++ {
array[i] = rv.Index(i).Interface()
}
case reflect.Struct:
rt := rv.Type()
array = make([]interface{}, 0)
for i := 0; i < rv.NumField(); i++ {
// Only public attributes.
if !utilstr.IsLetterUpper(rt.Field(i).Name[0]) {
continue
}
array = append(array, rv.Field(i).Interface())
}
default:
return []interface{}{i}
}
}
return array
}
}

View File

@ -0,0 +1,199 @@
// Copyright 2019 gf Author(https://github.com/gogf/gf). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package gconv
// SliceFloat is alias of Floats.
func SliceFloat(i interface{}) []float64 {
return Floats(i)
}
// SliceFloat32 is alias of Float32s.
func SliceFloat32(i interface{}) []float32 {
return Float32s(i)
}
// SliceFloat64 is alias of Float64s.
func SliceFloat64(i interface{}) []float64 {
return Floats(i)
}
// Floats converts <i> to []float64.
func Floats(i interface{}) []float64 {
return Float64s(i)
}
// Float32s converts <i> to []float32.
func Float32s(i interface{}) []float32 {
if i == nil {
return nil
}
if r, ok := i.([]float32); ok {
return r
} else {
var array []float32
switch value := i.(type) {
case []string:
array = make([]float32, len(value))
for k, v := range value {
array[k] = Float32(v)
}
case []int:
array = make([]float32, len(value))
for k, v := range value {
array[k] = Float32(v)
}
case []int8:
array = make([]float32, len(value))
for k, v := range value {
array[k] = Float32(v)
}
case []int16:
array = make([]float32, len(value))
for k, v := range value {
array[k] = Float32(v)
}
case []int32:
array = make([]float32, len(value))
for k, v := range value {
array[k] = Float32(v)
}
case []int64:
array = make([]float32, len(value))
for k, v := range value {
array[k] = Float32(v)
}
case []uint:
for _, v := range value {
array = append(array, Float32(v))
}
case []uint8:
array = make([]float32, len(value))
for k, v := range value {
array[k] = Float32(v)
}
case []uint16:
array = make([]float32, len(value))
for k, v := range value {
array[k] = Float32(v)
}
case []uint32:
array = make([]float32, len(value))
for k, v := range value {
array[k] = Float32(v)
}
case []uint64:
array = make([]float32, len(value))
for k, v := range value {
array[k] = Float32(v)
}
case []bool:
array = make([]float32, len(value))
for k, v := range value {
array[k] = Float32(v)
}
case []float64:
array = make([]float32, len(value))
for k, v := range value {
array[k] = Float32(v)
}
case []interface{}:
array = make([]float32, len(value))
for k, v := range value {
array[k] = Float32(v)
}
default:
return []float32{Float32(i)}
}
return array
}
}
// Float64s converts <i> to []float64.
func Float64s(i interface{}) []float64 {
if i == nil {
return nil
}
if r, ok := i.([]float64); ok {
return r
} else {
var array []float64
switch value := i.(type) {
case []string:
array = make([]float64, len(value))
for k, v := range value {
array[k] = Float64(v)
}
case []int:
array = make([]float64, len(value))
for k, v := range value {
array[k] = Float64(v)
}
case []int8:
array = make([]float64, len(value))
for k, v := range value {
array[k] = Float64(v)
}
case []int16:
array = make([]float64, len(value))
for k, v := range value {
array[k] = Float64(v)
}
case []int32:
array = make([]float64, len(value))
for k, v := range value {
array[k] = Float64(v)
}
case []int64:
array = make([]float64, len(value))
for k, v := range value {
array[k] = Float64(v)
}
case []uint:
for _, v := range value {
array = append(array, Float64(v))
}
case []uint8:
array = make([]float64, len(value))
for k, v := range value {
array[k] = Float64(v)
}
case []uint16:
array = make([]float64, len(value))
for k, v := range value {
array[k] = Float64(v)
}
case []uint32:
array = make([]float64, len(value))
for k, v := range value {
array[k] = Float64(v)
}
case []uint64:
array = make([]float64, len(value))
for k, v := range value {
array[k] = Float64(v)
}
case []bool:
array = make([]float64, len(value))
for k, v := range value {
array[k] = Float64(v)
}
case []float32:
array = make([]float64, len(value))
for k, v := range value {
array[k] = Float64(v)
}
case []interface{}:
array = make([]float64, len(value))
for k, v := range value {
array[k] = Float64(v)
}
default:
return []float64{Float64(i)}
}
return array
}
}

View File

@ -0,0 +1,310 @@
// Copyright 2019 gf Author(https://github.com/gogf/gf). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package gconv
// SliceInt is alias of Ints.
func SliceInt(i interface{}) []int {
return Ints(i)
}
// SliceInt32 is alias of Int32s.
func SliceInt32(i interface{}) []int32 {
return Int32s(i)
}
// SliceInt is alias of Int64s.
func SliceInt64(i interface{}) []int64 {
return Int64s(i)
}
// Ints converts <i> to []int.
func Ints(i interface{}) []int {
if i == nil {
return nil
}
if r, ok := i.([]int); ok {
return r
} else {
var array []int
switch value := i.(type) {
case []string:
array = make([]int, len(value))
for k, v := range value {
array[k] = Int(v)
}
case []int8:
array = make([]int, len(value))
for k, v := range value {
array[k] = int(v)
}
case []int16:
array = make([]int, len(value))
for k, v := range value {
array[k] = int(v)
}
case []int32:
array = make([]int, len(value))
for k, v := range value {
array[k] = int(v)
}
case []int64:
array = make([]int, len(value))
for k, v := range value {
array[k] = int(v)
}
case []uint:
array = make([]int, len(value))
for k, v := range value {
array[k] = int(v)
}
case []uint8:
array = make([]int, len(value))
for k, v := range value {
array[k] = int(v)
}
case []uint16:
array = make([]int, len(value))
for k, v := range value {
array[k] = int(v)
}
case []uint32:
array = make([]int, len(value))
for k, v := range value {
array[k] = int(v)
}
case []uint64:
array = make([]int, len(value))
for k, v := range value {
array[k] = int(v)
}
case []bool:
array = make([]int, len(value))
for k, v := range value {
if v {
array[k] = 1
} else {
array[k] = 0
}
}
case []float32:
array = make([]int, len(value))
for k, v := range value {
array[k] = Int(v)
}
case []float64:
array = make([]int, len(value))
for k, v := range value {
array[k] = Int(v)
}
case []interface{}:
array = make([]int, len(value))
for k, v := range value {
array[k] = Int(v)
}
case [][]byte:
array = make([]int, len(value))
for k, v := range value {
array[k] = Int(v)
}
default:
return []int{Int(i)}
}
return array
}
}
// Int32s converts <i> to []int32.
func Int32s(i interface{}) []int32 {
if i == nil {
return nil
}
if r, ok := i.([]int32); ok {
return r
} else {
var array []int32
switch value := i.(type) {
case []string:
array = make([]int32, len(value))
for k, v := range value {
array[k] = Int32(v)
}
case []int:
array = make([]int32, len(value))
for k, v := range value {
array[k] = int32(v)
}
case []int8:
array = make([]int32, len(value))
for k, v := range value {
array[k] = int32(v)
}
case []int16:
array = make([]int32, len(value))
for k, v := range value {
array[k] = int32(v)
}
case []int64:
array = make([]int32, len(value))
for k, v := range value {
array[k] = int32(v)
}
case []uint:
array = make([]int32, len(value))
for k, v := range value {
array[k] = int32(v)
}
case []uint8:
array = make([]int32, len(value))
for k, v := range value {
array[k] = int32(v)
}
case []uint16:
array = make([]int32, len(value))
for k, v := range value {
array[k] = int32(v)
}
case []uint32:
array = make([]int32, len(value))
for k, v := range value {
array[k] = int32(v)
}
case []uint64:
array = make([]int32, len(value))
for k, v := range value {
array[k] = int32(v)
}
case []bool:
array = make([]int32, len(value))
for k, v := range value {
if v {
array[k] = 1
} else {
array[k] = 0
}
}
case []float32:
array = make([]int32, len(value))
for k, v := range value {
array[k] = Int32(v)
}
case []float64:
array = make([]int32, len(value))
for k, v := range value {
array[k] = Int32(v)
}
case []interface{}:
array = make([]int32, len(value))
for k, v := range value {
array[k] = Int32(v)
}
case [][]byte:
array = make([]int32, len(value))
for k, v := range value {
array[k] = Int32(v)
}
default:
return []int32{Int32(i)}
}
return array
}
}
// Int64s converts <i> to []int64.
func Int64s(i interface{}) []int64 {
if i == nil {
return nil
}
if r, ok := i.([]int64); ok {
return r
} else {
var array []int64
switch value := i.(type) {
case []string:
array = make([]int64, len(value))
for k, v := range value {
array[k] = Int64(v)
}
case []int:
array = make([]int64, len(value))
for k, v := range value {
array[k] = int64(v)
}
case []int8:
array = make([]int64, len(value))
for k, v := range value {
array[k] = int64(v)
}
case []int16:
array = make([]int64, len(value))
for k, v := range value {
array[k] = int64(v)
}
case []int32:
array = make([]int64, len(value))
for k, v := range value {
array[k] = int64(v)
}
case []uint:
array = make([]int64, len(value))
for k, v := range value {
array[k] = int64(v)
}
case []uint8:
array = make([]int64, len(value))
for k, v := range value {
array[k] = int64(v)
}
case []uint16:
array = make([]int64, len(value))
for k, v := range value {
array[k] = int64(v)
}
case []uint32:
array = make([]int64, len(value))
for k, v := range value {
array[k] = int64(v)
}
case []uint64:
array = make([]int64, len(value))
for k, v := range value {
array[k] = int64(v)
}
case []bool:
array = make([]int64, len(value))
for k, v := range value {
if v {
array[k] = 1
} else {
array[k] = 0
}
}
case []float32:
array = make([]int64, len(value))
for k, v := range value {
array[k] = Int64(v)
}
case []float64:
array = make([]int64, len(value))
for k, v := range value {
array[k] = Int64(v)
}
case []interface{}:
array = make([]int64, len(value))
for k, v := range value {
array[k] = Int64(v)
}
case [][]byte:
array = make([]int64, len(value))
for k, v := range value {
array[k] = Int64(v)
}
default:
return []int64{Int64(i)}
}
return array
}
}

View File

@ -0,0 +1,104 @@
// Copyright 2019 gf Author(https://github.com/gogf/gf). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package gconv
// SliceStr is alias of Strings.
func SliceStr(i interface{}) []string {
return Strings(i)
}
// Strings converts <i> to []string.
func Strings(i interface{}) []string {
if i == nil {
return nil
}
if r, ok := i.([]string); ok {
return r
} else {
var array []string
switch value := i.(type) {
case []int:
array = make([]string, len(value))
for k, v := range value {
array[k] = String(v)
}
case []int8:
array = make([]string, len(value))
for k, v := range value {
array[k] = String(v)
}
case []int16:
array = make([]string, len(value))
for k, v := range value {
array[k] = String(v)
}
case []int32:
array = make([]string, len(value))
for k, v := range value {
array[k] = String(v)
}
case []int64:
array = make([]string, len(value))
for k, v := range value {
array[k] = String(v)
}
case []uint:
array = make([]string, len(value))
for k, v := range value {
array[k] = String(v)
}
case []uint8:
array = make([]string, len(value))
for k, v := range value {
array[k] = String(v)
}
case []uint16:
array = make([]string, len(value))
for k, v := range value {
array[k] = String(v)
}
case []uint32:
array = make([]string, len(value))
for k, v := range value {
array[k] = String(v)
}
case []uint64:
array = make([]string, len(value))
for k, v := range value {
array[k] = String(v)
}
case []bool:
array = make([]string, len(value))
for k, v := range value {
array[k] = String(v)
}
case []float32:
array = make([]string, len(value))
for k, v := range value {
array[k] = String(v)
}
case []float64:
array = make([]string, len(value))
for k, v := range value {
array[k] = String(v)
}
case []interface{}:
array = make([]string, len(value))
for k, v := range value {
array[k] = String(v)
}
case [][]byte:
array = make([]string, len(value))
for k, v := range value {
array[k] = String(v)
}
default:
return []string{String(i)}
}
return array
}
}

View File

@ -0,0 +1,295 @@
// Copyright 2019 gf Author(https://github.com/gogf/gf). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package gconv
// SliceUint is alias of Uints.
func SliceUint(i interface{}) []uint {
return Uints(i)
}
// SliceUint32 is alias of Uint32s.
func SliceUint32(i interface{}) []uint32 {
return Uint32s(i)
}
// SliceUint64 is alias of Uint64s.
func SliceUint64(i interface{}) []uint64 {
return Uint64s(i)
}
// Uints converts <i> to []uint.
func Uints(i interface{}) []uint {
if i == nil {
return nil
}
if r, ok := i.([]uint); ok {
return r
} else {
var array []uint
switch value := i.(type) {
case []string:
array = make([]uint, len(value))
for k, v := range value {
array[k] = Uint(v)
}
case []int8:
array = make([]uint, len(value))
for k, v := range value {
array[k] = uint(v)
}
case []int16:
array = make([]uint, len(value))
for k, v := range value {
array[k] = uint(v)
}
case []int32:
array = make([]uint, len(value))
for k, v := range value {
array[k] = uint(v)
}
case []int64:
array = make([]uint, len(value))
for k, v := range value {
array[k] = uint(v)
}
case []uint8:
array = make([]uint, len(value))
for k, v := range value {
array[k] = uint(v)
}
case []uint16:
array = make([]uint, len(value))
for k, v := range value {
array[k] = uint(v)
}
case []uint32:
array = make([]uint, len(value))
for k, v := range value {
array[k] = uint(v)
}
case []uint64:
array = make([]uint, len(value))
for k, v := range value {
array[k] = uint(v)
}
case []bool:
array = make([]uint, len(value))
for k, v := range value {
if v {
array[k] = 1
} else {
array[k] = 0
}
}
case []float32:
array = make([]uint, len(value))
for k, v := range value {
array[k] = Uint(v)
}
case []float64:
array = make([]uint, len(value))
for k, v := range value {
array[k] = Uint(v)
}
case []interface{}:
array = make([]uint, len(value))
for k, v := range value {
array[k] = Uint(v)
}
case [][]byte:
array = make([]uint, len(value))
for k, v := range value {
array[k] = Uint(v)
}
default:
return []uint{Uint(i)}
}
return array
}
}
// Uint32s converts <i> to []uint32.
func Uint32s(i interface{}) []uint32 {
if i == nil {
return nil
}
if r, ok := i.([]uint32); ok {
return r
} else {
var array []uint32
switch value := i.(type) {
case []string:
array = make([]uint32, len(value))
for k, v := range value {
array[k] = Uint32(v)
}
case []int8:
array = make([]uint32, len(value))
for k, v := range value {
array[k] = uint32(v)
}
case []int16:
array = make([]uint32, len(value))
for k, v := range value {
array[k] = uint32(v)
}
case []int32:
array = make([]uint32, len(value))
for k, v := range value {
array[k] = uint32(v)
}
case []int64:
array = make([]uint32, len(value))
for k, v := range value {
array[k] = uint32(v)
}
case []uint:
array = make([]uint32, len(value))
for k, v := range value {
array[k] = uint32(v)
}
case []uint8:
array = make([]uint32, len(value))
for k, v := range value {
array[k] = uint32(v)
}
case []uint16:
array = make([]uint32, len(value))
for k, v := range value {
array[k] = uint32(v)
}
case []uint64:
array = make([]uint32, len(value))
for k, v := range value {
array[k] = uint32(v)
}
case []bool:
array = make([]uint32, len(value))
for k, v := range value {
if v {
array[k] = 1
} else {
array[k] = 0
}
}
case []float32:
array = make([]uint32, len(value))
for k, v := range value {
array[k] = Uint32(v)
}
case []float64:
array = make([]uint32, len(value))
for k, v := range value {
array[k] = Uint32(v)
}
case []interface{}:
array = make([]uint32, len(value))
for k, v := range value {
array[k] = Uint32(v)
}
case [][]byte:
array = make([]uint32, len(value))
for k, v := range value {
array[k] = Uint32(v)
}
default:
return []uint32{Uint32(i)}
}
return array
}
}
// Uint64s converts <i> to []uint64.
func Uint64s(i interface{}) []uint64 {
if i == nil {
return nil
}
if r, ok := i.([]uint64); ok {
return r
} else {
var array []uint64
switch value := i.(type) {
case []string:
array = make([]uint64, len(value))
for k, v := range value {
array[k] = Uint64(v)
}
case []int8:
array = make([]uint64, len(value))
for k, v := range value {
array[k] = uint64(v)
}
case []int16:
array = make([]uint64, len(value))
for k, v := range value {
array[k] = uint64(v)
}
case []int32:
array = make([]uint64, len(value))
for k, v := range value {
array[k] = uint64(v)
}
case []int64:
array = make([]uint64, len(value))
for k, v := range value {
array[k] = uint64(v)
}
case []uint:
array = make([]uint64, len(value))
for k, v := range value {
array[k] = uint64(v)
}
case []uint8:
array = make([]uint64, len(value))
for k, v := range value {
array[k] = uint64(v)
}
case []uint16:
array = make([]uint64, len(value))
for k, v := range value {
array[k] = uint64(v)
}
case []uint32:
array = make([]uint64, len(value))
for k, v := range value {
array[k] = uint64(v)
}
case []bool:
array = make([]uint64, len(value))
for k, v := range value {
if v {
array[k] = 1
} else {
array[k] = 0
}
}
case []float32:
array = make([]uint64, len(value))
for k, v := range value {
array[k] = Uint64(v)
}
case []float64:
array = make([]uint64, len(value))
for k, v := range value {
array[k] = Uint64(v)
}
case []interface{}:
array = make([]uint64, len(value))
for k, v := range value {
array[k] = Uint64(v)
}
case [][]byte:
array = make([]uint64, len(value))
for k, v := range value {
array[k] = Uint64(v)
}
default:
return []uint64{Uint64(i)}
}
return array
}
}

View File

@ -0,0 +1,98 @@
// Copyright 2019 gf Author(https://github.com/gogf/gf). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package gconv_test
import (
"testing"
"github.com/gogf/gf/frame/g"
"github.com/gogf/gf/test/gtest"
"github.com/gogf/gf/util/gconv"
)
func Test_Struct_Slice(t *testing.T) {
gtest.Case(t, func() {
type User struct {
Scores []int
}
user := new(User)
array := g.Slice{1, 2, 3}
err := gconv.Struct(g.Map{"scores": array}, user)
gtest.Assert(err, nil)
gtest.Assert(user.Scores, array)
})
gtest.Case(t, func() {
type User struct {
Scores []int32
}
user := new(User)
array := g.Slice{1, 2, 3}
err := gconv.Struct(g.Map{"scores": array}, user)
gtest.Assert(err, nil)
gtest.Assert(user.Scores, array)
})
gtest.Case(t, func() {
type User struct {
Scores []int64
}
user := new(User)
array := g.Slice{1, 2, 3}
err := gconv.Struct(g.Map{"scores": array}, user)
gtest.Assert(err, nil)
gtest.Assert(user.Scores, array)
})
gtest.Case(t, func() {
type User struct {
Scores []uint
}
user := new(User)
array := g.Slice{1, 2, 3}
err := gconv.Struct(g.Map{"scores": array}, user)
gtest.Assert(err, nil)
gtest.Assert(user.Scores, array)
})
gtest.Case(t, func() {
type User struct {
Scores []uint32
}
user := new(User)
array := g.Slice{1, 2, 3}
err := gconv.Struct(g.Map{"scores": array}, user)
gtest.Assert(err, nil)
gtest.Assert(user.Scores, array)
})
gtest.Case(t, func() {
type User struct {
Scores []uint64
}
user := new(User)
array := g.Slice{1, 2, 3}
err := gconv.Struct(g.Map{"scores": array}, user)
gtest.Assert(err, nil)
gtest.Assert(user.Scores, array)
})
gtest.Case(t, func() {
type User struct {
Scores []float32
}
user := new(User)
array := g.Slice{1, 2, 3}
err := gconv.Struct(g.Map{"scores": array}, user)
gtest.Assert(err, nil)
gtest.Assert(user.Scores, array)
})
gtest.Case(t, func() {
type User struct {
Scores []float64
}
user := new(User)
array := g.Slice{1, 2, 3}
err := gconv.Struct(g.Map{"scores": array}, user)
gtest.Assert(err, nil)
gtest.Assert(user.Scores, array)
})
}