在不参考其类型的情况下分配空切片?

我的代码调用了一个大致如下所示的库函数:


func Search() ([]myLibrary.SomeObject, error) {

    var results []apiv17.SomeObject

    // ...

    if (resultsFound) {

      results = append(results, someResult)

    }

    return results

}

...我的代码调用它,然后将其编组为 JSON。


results, err := myLibrary.Search()

bytes, err := json.Marshal(results)

现在的问题是,由于Search函数的编写方式(假设我们无法更改它),nil如果没有结果,它将返回一个未初始化的切片。不幸的是,没有办法配置encoding/json为将 nil 切片编码为(例如,请参阅正在进行的讨论中的[]此提案)。


明确检查nil解决问题:


results, err := myLibrary.Search()

if results == nil {

  results = []apiv17.SomeObject{}

}

bytes, err := json.Marshal(results)

...但它也增加了对返回类型的显式依赖,apiv17.SomeObject. 这很不方便,因为该类型在库中经常更改。例如,在下一个库版本中它可能是apiv18.SomeObject.


通过nil上面的检查,每次发生这种情况时我都必须更新我的代码。


有什么办法可以避免这种情况,并在不显式引用其类型的情况下为变量分配一个空的、非零的切片?是这样的:


results = [](type of results){}


红糖糍粑
浏览 87回答 2
2回答

POPMUISE

去 1.18您可以使用通用函数来捕获切片的基本类型并返回长度为零的切片:func echo[T any](v []T) []T {    return make([]T, 0)}func main() {    n := foo.GetFooBar()    if n == nil {        n = echo(n) // no need to refer to apiv17 here    }    bytes, _ := json.Marshal(n)    fmt.Println(string(bytes)) // prints []}需要常规参数v []Tin的目的echo是允许类型推断将切片[]apiv17.SomeObject与参数统一[]T并推断T为基本类型apiv17.SomeObject,这样您就可以调用它,echo(n)而无需显式类型参数。该包apiv17当然在编译时是已知的,因为它是通过 传递导入的myPackage,因此您可以利用这一点和类型推断来避免为 . 添加显式import语句apiv17。这就是它在多文件游乐场上的样子:https ://go.dev/play/p/4ycTkaGLFpo该类型在bar包中声明,但main仅导入play.ground/foo且仅使用foo.GetFooBar.转到 1.17 及以下版本反射。只需将echo上面的函数更改为接受interface{}参数(anyGo 1.17 中没有,还记得吗?),然后执行以下操作reflect.MakeSlice:func set(v interface{}) {    rv := reflect.ValueOf(v)    if rv.Kind() != reflect.Ptr {        panic("not a ptr")    }    reflect.Indirect(rv).Set(reflect.MakeSlice(rv.Type().Elem(), 0, 0))}然后传递一个指向切片的指针,这样你就可以用反射来设置它的值。func main() {    n := foo.GetFooBar()    if n == nil {        set(&n)    }    fmt.Printf("type: %T, val: %v, is nil: %t\n", n, n, n == nil)    // type: []bar.FooBar, val: [], is nil: false        bytes, _ := json.Marshal(n)    fmt.Println(string(bytes)) // prints [] again}Go 1.17 游乐场:https ://go.dev/play/p/4jMkr22LMF7?v=goprev

慕斯王

另一个答案描述了如何创建一个空切片。但是你可以更简单地解决你原来的问题:如果results是nil,你不需要创建一个空切片,不管它有什么元素类型,[]无论如何 JSON 封送处理都是。因此,如果results是nil,则无需调用json.Marshal(),只需“输出”即可[]:results, err := myLibrary.Search()var bytes []byteif results == nil {    bytes = []byte{'[', ']' } // JSON marshaling result is "[]"} else {    bytes, err = json.Marshal(results)    // Handle error}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go