如何制作界面切片和附加值
How to make interface slice and append value
我想做一个函数,从一个字符串数组中解析出一个slice(一种抽象的解析方式,可以是JSON、msgpack或XML)。这个slice的类型是不确定的,可以是[]A或者[]*A。但是现在我遇到了一个问题。你能帮帮我吗
func unmarshalSlice(strings []string, to interface{}) (err error) {
elementType := reflect.TypeOf(to).Elem()
to = reflect.MakeSlice(reflect.SliceOf(elementType), 0, len(strings))
for _, str := range strings {
value := reflect.New(elementType).Interface()
if err = json.Unmarshal([]byte(str), value); nil != err {
return
}
to = reflect.Append(to.(reflect.Value), reflect.ValueOf(value).Elem())
}
return
}
测试代码为
func TestUnmarshalSlice(t *testing.T) {
var members []*Member
_ = unmarshalSlice([]string{
`{
"Value": "store"
}`, `{
"Value": "zhang"
}`,
}, members)
fmt.Println(members)
}
我已经更正了您的 unmarshalSlice
函数中的一些行。
首先,您必须创建发送类型的切片,然后将这些类型值附加到该切片。最后将该切片分配为已发送可分配接口的值。
并调用具有可分配类型的 unmarshalSlice
函数。
type Member struct {
Value string
}
func TestUnmarshalSlice(t *testing.T) {
var members []Member
_ = unmarshalSlice([]string{
`{
"Value": "store"
}`, `{
"Value": "zhang"
}`,
}, &members)
fmt.Println(members[0], members[1]) //Output: {store} {zhang}
}
func TestUnmarshalPointerSlice(t *testing.T) {
var members []*Member
_ = unmarshalSlice([]string{
`{
"Value": "store"
}`, `{
"Value": "zhang"
}`,
}, &members)
fmt.Println(members[0], members[1]) //Output: &{store} &{zhang}
}
func unmarshalSlice(strings []string, to interface{}) (err error) {
elementType := reflect.TypeOf(to).Elem().Elem()
// create slice of *Member{}
o := reflect.MakeSlice(reflect.TypeOf(to).Elem(), 0, len(strings))
for _, str := range strings {
// create empty assignable Member{}
value := reflect.New(elementType).Interface()
if err = json.Unmarshal([]byte(str), value); nil != err {
return
}
// append *Member{} to slice
o = reflect.Append(o, reflect.ValueOf(value).Elem())
}
// set created slice to the value of "to"
reflect.ValueOf(to).Elem().Set(o)
return
}
你可以运行测试here
我不相信您期望从该功能获得的灵活性是一件好事...
无论如何,很快(当泛型被添加到 Go 1.18 中的语言中时),您将能够编写一个签名略有不同的泛型函数来执行您想要的操作 ,而无需求助于反射:
package main
import (
"encoding/json"
"fmt"
"os"
)
type Member struct {
Value string
}
func unmarshalSlice[T any](ss []string) ([]T, error) {
ts := make([]T, 0, len(ss))
for _, str := range ss {
var t T
if err := json.Unmarshal([]byte(str), &t); err != nil {
return nil, err
}
ts = append(ts, t)
}
return ts, nil
}
func main() {
input := []string{
`{"Value": "store"}`,
`{"Value": "zhang"}`,
}
members, err := unmarshalSlice[Member](input)
if err != nil {
fmt.Fprint(os.Stderr, err)
os.Exit(1)
}
fmt.Println(members)
pmembers, err := unmarshalSlice[*Member](input)
if err != nil {
fmt.Fprint(os.Stderr, err)
os.Exit(1)
}
for _, m := range pmembers {
fmt.Println(*m)
}
}
输出:
[{store} {zhang}]
{store}
{zhang}
您不需要那么复杂的代码。看看这个非常简单的解决方案
package main
import (
"encoding/json"
"fmt"
"strings"
)
type Member struct {
Value string
}
func main() {
inputs := []string{
`{
"Value": "store"
}`, `{
"Value": "zhang"
}`,
}
var members []Member
s := strings.Join(inputs, ",")
s = strings.TrimSuffix(s, ",")
s = fmt.Sprintf("[%v]", s)
json.Unmarshal([]byte(s), &members)
fmt.Println(members[0], members[1])
var out []*Member
json.Unmarshal([]byte(s), &out)
fmt.Println(out[0], out[1])
}
我想做一个函数,从一个字符串数组中解析出一个slice(一种抽象的解析方式,可以是JSON、msgpack或XML)。这个slice的类型是不确定的,可以是[]A或者[]*A。但是现在我遇到了一个问题。你能帮帮我吗
func unmarshalSlice(strings []string, to interface{}) (err error) {
elementType := reflect.TypeOf(to).Elem()
to = reflect.MakeSlice(reflect.SliceOf(elementType), 0, len(strings))
for _, str := range strings {
value := reflect.New(elementType).Interface()
if err = json.Unmarshal([]byte(str), value); nil != err {
return
}
to = reflect.Append(to.(reflect.Value), reflect.ValueOf(value).Elem())
}
return
}
测试代码为
func TestUnmarshalSlice(t *testing.T) {
var members []*Member
_ = unmarshalSlice([]string{
`{
"Value": "store"
}`, `{
"Value": "zhang"
}`,
}, members)
fmt.Println(members)
}
我已经更正了您的 unmarshalSlice
函数中的一些行。
首先,您必须创建发送类型的切片,然后将这些类型值附加到该切片。最后将该切片分配为已发送可分配接口的值。
并调用具有可分配类型的 unmarshalSlice
函数。
type Member struct {
Value string
}
func TestUnmarshalSlice(t *testing.T) {
var members []Member
_ = unmarshalSlice([]string{
`{
"Value": "store"
}`, `{
"Value": "zhang"
}`,
}, &members)
fmt.Println(members[0], members[1]) //Output: {store} {zhang}
}
func TestUnmarshalPointerSlice(t *testing.T) {
var members []*Member
_ = unmarshalSlice([]string{
`{
"Value": "store"
}`, `{
"Value": "zhang"
}`,
}, &members)
fmt.Println(members[0], members[1]) //Output: &{store} &{zhang}
}
func unmarshalSlice(strings []string, to interface{}) (err error) {
elementType := reflect.TypeOf(to).Elem().Elem()
// create slice of *Member{}
o := reflect.MakeSlice(reflect.TypeOf(to).Elem(), 0, len(strings))
for _, str := range strings {
// create empty assignable Member{}
value := reflect.New(elementType).Interface()
if err = json.Unmarshal([]byte(str), value); nil != err {
return
}
// append *Member{} to slice
o = reflect.Append(o, reflect.ValueOf(value).Elem())
}
// set created slice to the value of "to"
reflect.ValueOf(to).Elem().Set(o)
return
}
你可以运行测试here
我不相信您期望从该功能获得的灵活性是一件好事...
无论如何,很快(当泛型被添加到 Go 1.18 中的语言中时),您将能够编写一个签名略有不同的泛型函数来执行您想要的操作 ,而无需求助于反射:
package main
import (
"encoding/json"
"fmt"
"os"
)
type Member struct {
Value string
}
func unmarshalSlice[T any](ss []string) ([]T, error) {
ts := make([]T, 0, len(ss))
for _, str := range ss {
var t T
if err := json.Unmarshal([]byte(str), &t); err != nil {
return nil, err
}
ts = append(ts, t)
}
return ts, nil
}
func main() {
input := []string{
`{"Value": "store"}`,
`{"Value": "zhang"}`,
}
members, err := unmarshalSlice[Member](input)
if err != nil {
fmt.Fprint(os.Stderr, err)
os.Exit(1)
}
fmt.Println(members)
pmembers, err := unmarshalSlice[*Member](input)
if err != nil {
fmt.Fprint(os.Stderr, err)
os.Exit(1)
}
for _, m := range pmembers {
fmt.Println(*m)
}
}
输出:
[{store} {zhang}]
{store}
{zhang}
您不需要那么复杂的代码。看看这个非常简单的解决方案
package main
import (
"encoding/json"
"fmt"
"strings"
)
type Member struct {
Value string
}
func main() {
inputs := []string{
`{
"Value": "store"
}`, `{
"Value": "zhang"
}`,
}
var members []Member
s := strings.Join(inputs, ",")
s = strings.TrimSuffix(s, ",")
s = fmt.Sprintf("[%v]", s)
json.Unmarshal([]byte(s), &members)
fmt.Println(members[0], members[1])
var out []*Member
json.Unmarshal([]byte(s), &out)
fmt.Println(out[0], out[1])
}