在Go语言中,具有空结构体类型的作用是什么?

41

为什么要创建一个空结构类型?

type FrontierSigner struct{}

它有什么用处?


3
https://dave.cheney.net/2014/03/25/the-empty-struct - user539810
1
请访问以下链接以查看关于编程的相关内容的中文翻译:https://dev59.com/GWIi5IYBdhLWcg3w9gNy https://dev59.com/xGEh5IYBdhLWcg3wIgbN - Josh Lee
@ChronoKitsune,我在发布之前已经阅读了它,但我仍然不理解。首先,“方法接收器”是什么? - Nulik
@Adrian,如果可以省略null方法接收器,为什么会有人使用它呢?这只是额外的打字工作。 - Nulik
我不确定我理解这个问题,但我知道编程的目标不是为了最小化打字。 - Adrian
显示剩余2条评论
3个回答

101
在Go语言中,空结构体struct{}以一种特殊的方式实现。
0. 这是Go语言中最小的构建块。它的大小实际上是0字节。
1. 如果它的大小为零,你可以创建一个包含1000个空结构的切片,这个切片会非常小。因为实际上Go只在切片中存储了它们的数量,而不是它们本身。通道也是同样的情况。
2. 所有指向它的指针都指向内存中的同一个特殊位置。
3. 在通道中非常有用,当你通知某个事件但不需要传递任何关于它的信息时,最好的解决方案是传递一个空结构,因为它只会在通道中增加一个计数器,而不会分配内存、复制元素等等。有时人们会使用布尔值来实现这个目的,但这样做要差得多。
4. 方法的零大小容器。你可能想要为接口进行测试而创建一个模拟对象。通常你不需要其中的数据,只需要预定义输入和输出的方法。
5. Go语言没有Set对象,但可以很容易地通过`map[keyType]struct{}`来实现。这样,map只保留键而不保留值。
6. 空结构体被用作一种类型来实现接口。这在接收器方法中可以看到。

1
比起 Dave Cheney 网站上的回答,这个回答更加有用。谢谢! - Nulik

9

我通常在需要布尔值的地方使用它。例如,代替以下代码:

func main() {
    done := make(chan bool, 1)

    go func() {
        // simulate long running task
        time.Sleep(4 * time.Second)
        done <- true
        fmt.Println("long running task is done")
    }()

    <-done
    close(done)

    fmt.Printf("whole program is done.")
}

我使用;
package main

import (
    "fmt"
    "time"
)

func main() {
    done := make(chan struct{}, 1)

    go func() {
        // simulate long running task
        time.Sleep(4 * time.Second)
        done <- struct{}{}
        fmt.Println("long running task is done")
    }()

    <-done
    close(done)

    fmt.Printf("whole program is done.")
}

1
在生成的Go协程中关闭通道更简单。如果选择推送值,则关闭通道也是不必要的。 - jdizzle

3

以下是空结构体在 IT 技术中的另一种应用,参考链接

  • 使用空结构体{}来将方法分组
  • 方法不捕获接收器
type Codec interface {
    Encode(w io.Writer, v interface{}) error
    Decode(r io.Reader, v interface{}) error
}    

type jsonCodec struct{}
func (jsonCodec) Encode(w io.Writer, v interface{}) error {
    return json.NewEncoder(w).Encode(v)
}
func (jsonCodec) Decode(r io.Reader, v interface{}) error {
    return json.NewDecoder(r).Decode(v)
}    

var JSON Codec = jsonCodec{}

func main() {
    sobj := struct {
        S1 string `json:"s1"`
        K3 string `json:"k3"`
    }{}
    ss := `{"s1": "v1", "k3": "vv3"}`
    err := JSON.Decode(strings.NewReader(ss), &sobj)
    if err != nil {
        fmt.Println(err)
    }

    fmt.Println(sobj)
}

这是一个简单的API,JSON变量不会暴露jsonCodec类型。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接