gpt4 book ai didi

go - 如何在Golang中通过引用传递具有值类型接口(interface)的 map slice

转载 作者:IT王子 更新时间:2023-10-29 01:58:39 25 4
gpt4 key购买 nike

我要通过[]map[string]interface{}通过引用一个函数。这是我的尝试。

package main

import "fmt"

func main() {

b := map[string]int{"foo": 1, "bar": 2}
a := [...]map[string]int{b}

fmt.Println(a)

editit(a)

fmt.Println(a)
}

func editit(a interface{}) {
fmt.Println(a)

b := map[string]int{"foo": 3, "bar": 4}
a = [...]map[string]int{b}

fmt.Println(a)
}

https://play.golang.org/p/9Bt15mvud1

这是另一种尝试,也是我最终想要做的。这不编译。
func (self BucketStats) GetSamples() {

buckets := []make(map[string]interface{})
self.GetAuthRequest(self.url, &buckets)

//ProcessBuckets()
}

func (self BucketStats) GetAuthRequest(rurl string, **data interface{}) (err error) {
client := &http.Client{}

req, err := http.NewRequest("GET", rurl, nil)
req.SetBasicAuth(self.un, self.pw)
resp, err := client.Do(req)
if err != nil {
return
}

body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return
}

// it's all for this!!!
err = json.Unmarshal(body, data)

return
}

最佳答案

这里有几件事不对。

一、[...]map[string]int{b}实际上不是一个 slice ,而是一个定长数组。 [...]语法的意思是“制作一个数组,并在编译时根据放入的内容设置长度”。 slice 语法很简单 []map[string]int{b} .因此,您调用 editit(a)实际上是传递数组的副本,而不是引用( slice 是天生的引用,数组不是)。当aeditit() 中重新分配,您正在重新分配副本,而不是原件,因此没有任何变化。

其次,使用指向接口(interface)的指针几乎没有用处。事实上,Go 运行时已经改回了几个版本,不会自动取消对接口(interface)的指针的引用(就像它对几乎所有其他东西的指针所做的那样),以阻止这种习惯。接口(interface)已经是天生的引用,所以没有理由创建一个指向一个的指针。

第三,您实际上不需要在此处传递对接口(interface)的引用。您正试图解码到该接口(interface)中包含的基本数据结构。您实际上并不关心界面本身。 GetAuthRequest(rurl string, data interface{})在这里工作得很好。

func (self BucketStats) GetSamples() {

var buckets []map[string]interface{}
self.GetAuthRequest(self.url, &buckets)

//ProcessBuckets()
}

func (self BucketStats) GetAuthRequest(rurl string, data interface{}) (err error) {
client := &http.Client{}

req, err := http.NewRequest("GET", rurl, nil)
req.SetBasicAuth(self.un, self.pw)
resp, err := client.Do(req)
if err != nil {
return
}

body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return
}

// it's all for this!!!
err = json.Unmarshal(body, data)

return
}

让我按顺序带您了解究竟发生了什么:
  • buckets := var buckets []map[string]interface{}我们在这里不需要制造,因为 json.Unmarshal()会为我们填满它。
  • self.GetAuthRequest(self.url, &buckets)这会将引用传递到接口(interface)字段中。内GetAuthRequest , data是一个底层类型*[]map[string]interface{}的接口(interface)和一个底层值等于​​原始地址 buckets GetSamples() 中的变量.
  • err = json.Unmarshal(body, data)这通过接口(interface)data ,按值,到 json.Unmarshal() 的接口(interface)参数.内json.Unmarshal() , 它有新的界面 v基础类型 *[]map[string]interface{}和一个底层值等于​​原始地址 buckets GetSamples() 中的变量.该接口(interface)是一个不同的变量,在内存中具有不同的地址,与在 GetAuthRequest 中保存相同数据的接口(interface)不同。 ,但是数据被复制了,并且数据包含对您的 slice 的引用,所以您仍然很好。
  • json.Unmarshal()将通过反射,用请求中的数据填充您传递给它的接口(interface)所指向的 slice 。它引用了 slice 头 buckets你交了它,即使它通过两个接口(interface)到达那里,所以它所做的任何改变都会影响原来的buckets多变的。

  • 当你一路回到 ProcessBuckets() , buckets变量将包含您的所有数据。

    作为辅助建议,如果您的函数长度超过几行,请不要使用命名返回。最好显式返回您的变量。由于可变阴影,这尤其重要。例如,在您的 GetAuthRequest()函数,它永远不会返回非零错误。这是因为您声明了一个错误变量 err在函数签名中,但您立即使用局部变量 err 隐藏它使用 req, err := http.NewRequest("GET", rurl, nil) 中的简短声明.对于函数的其余部分, err现在指的是这个新的错误变量,而不是定义为返回变量的那个。结果回来的时候,原来的 err返回中的变量始终是 nil .更好的风格是:
    func (self BucketStats) GetAuthRequest(rurl string, **data interface{}) error {
    client := &http.Client{}

    req, err := http.NewRequest("GET", rurl, nil)
    req.SetBasicAuth(self.un, self.pw)
    resp, err := client.Do(req)
    if err != nil {
    return err
    }

    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
    return err
    }

    // it's all for this!!!
    return json.Unmarshal(body, data)
    }

    关于go - 如何在Golang中通过引用传递具有值类型接口(interface)的 map slice ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38728567/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com