what means two curly brackets in a row in structure 'struct' in Go lang?

huangapple go评论74阅读模式
英文:

what means two curly brackets in a row in structure 'struct' in Go lang?

问题

我在使用Golang的map时遇到了一种奇怪的形式。我用关键词"使用结构体时使用两个花括号"进行了搜索,但没有找到相关信息。在下面的代码中,"struct{}{}"的意思是什么?

menu := map[string]interface{}{
	"icecream": "delicious",
	"eggs": struct {
		price float64
	}{"chicken", 1.75}
}
英文:

I'm facing with kind of strange shape when I'm using map in Golang. I searched about it with keywords "using two curly brackets when using struct" but couldn't find. What does it mean using like below 'struct{}{}'?

menu := map[string]interface{}{
	"icecream": "delicious",
	"eggs":struct {
		price float64 
	}{"chicken", 1.75}   }

答案1

得分: 1

让我们来分解一下:

menu := map[string]interface{}{

创建一个名为menu的变量,类型为map[string]interface{}interface{}表示实现了一个没有方法的接口的任何类型,因此基本上可以分配任何类型)。最后一个开括号是实际数据写在其中的地方,所以:

foo := map[string]int{}
foo["bar"] = 1

可以写成

foo := map[string]int{
   "bar": 1,
}

现在在你的代码中,第一个键值对很简单:

"icecream": "delicious",

第二个键值对是你不清楚的部分:

"eggs":struct {
    price float64 
}{"chicken", 1.75}   }

现在这段代码无法编译,但让我们将其改为可以编译的形式:

"eggs":struct {
    kind  string
    price float64 
}{"chicken", 1.75}   }

我们在这里做的是向menu映射(类型为map[string]any)添加一个键,而键eggs的值是一个结构体。具体来说,是一个带有2个字段的匿名结构体:

struct {
    kind  string
    price float74
}

我们想要设置字段的特定值,所以我们必须初始化这个结构体:

struct {
    kind  string
    price float64 
}{"chicken", 1.75}

这与写成以下形式是相同的:

eggs := struct{
    kind  string
    price float64
}{
    kind:  "chicken",
    price: 1.75,
}

甚至可以这样写:

type Egg struct {
    kind  string
    price float64
}

menu := map[string]any{
    "icecream": "delicious",
    "eggs": Egg{
        kind:  "chicken",
        price: 1.75,
    },
}

在这里可能让你困惑的是在初始化结构体时省略了字段(这被认为是不好的形式,只有在字段的顺序被保留时才能正常工作)。假设像这样:

menu := map[string]any{
    "icecream": "delicious",
    "eggs": struct{
        kind  string
        price float64
    }{
        kind:  "chicken",
        price: 1.75,
    },
}

那么以下代码将无法工作:

menu := map[string]any{
    "icecream": "delicious",
    "eggs": struct{
        kind  string
        price float64
    }{
        1.75, // 结构体的第一个字段应为字符串
    },
}

但这样可以:

menu := map[string]any{
    "icecream": "delicious",
    "eggs": struct{
        kind  string
        price float64
    }{
        price: 1.75,
    },
}

总的来说,在测试中或用于(解)编组大型数据集的类型之外,很少见到这种情况。我认为我上次在代码中使用这种匿名结构体的时间是当我需要接收和传递XML数据块时,但不对其进行任何处理,我会创建类似于以下的类型:

type XMLInput struct {
    // 我实际需要使用的数据字段
    Details struct {
        // 需要确保设置的字段,但不进行任何处理,因此不需要可用的类型
    } `xml:"whatever_tag"`
}
英文:

So let's break this down:

menu := map[string]interface{}{

Creates a variable called menu, of type map[string]interface{} (interface{} being any type that implements an interface with zero methods, so basically any type can be assigned). The last opening bracket is where the actual data contained within this map can be written, so:

foo := map[string]int{}
foo["bar"] = 1

Can be written as

foo := map[string]int{
   "bar": 1,
}

Now in your code, the first key-value pair is simple:

"icecream": "delicious",

The second one is the one you're unclear about:

"eggs":struct {
    price float64 
}{"chicken", 1.75}   }

Now this code is not going to compile, but let's change it to something that will:

"eggs":struct {
    kind  string
    price float64 
}{"chicken", 1.75}   }

What we're doing here is adding a key to the meny map (type map[string]any), and the value assigned to the key eggs is a struct. Specifically an anonymous struct with 2 fields:

struct {
    kind  string
    price float74
}

We want to set the fields to certain values, so we have to initialise this struct:

struct {
    kind  string
    price float64 
}{"chicken", 1.75}

This is the same as writing:

eggs := struct{
    kind  string
    price float64
}{
    kind:  "chicken",
    price: 1.75,
}

Or even:

type Egg struct {
    kind  string
    price float64
}

menu := map[string]any{
    "icecream": "delicious",
    "eggs": Egg{
        kind:  "chicken",
        price: 1.75,
    },
}

The thing that probably threw you off here is the omission of the fields when initialising the struct (which is considered bad form, and only really works if the order of the fields is preserved. Assuming something like this:

menu := map[string]any{
    "icecream": "delicious",
    "eggs": struct{
        kind  string
        price float64
    }{
        kind:  "chicken",
        price: 1.75,
    },
}

Then the following code won't work:

menu := map[string]any{
    "icecream": "delicious",
    "eggs": struct{
        kind  string
        price float64
    }{
        1.75, // first field in struct is expected to be a string
    },
}

But this will:

menu := map[string]any{
    "icecream": "delicious",
    "eggs": struct{
        kind  string
        price float64
    }{
        price: 1.75,
    },
}

Overall, it's not that common to see things like this outside of tests, or types that are used to (un) marshal large data-sets where you don't need to use/separate subsets of the data. I think the last time I've used this kind of anonymous structs in code was when I had to receive and pass on chunks of XML data, but do no processing on it, I would create types like:

type XMLInput struct {
    // fields of data I actually needed to use
    Details struct {
        // fields that I needed to make sure were set, but didn't do any processing on, so I didn't need a usable type
    } `xml:"whatever_tag"`
}

huangapple
  • 本文由 发表于 2022年12月25日 21:50:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/74913663.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定