What is the use of empty struct in GoLang

English 简体中文 Tiếng Việt
Summary

Go's empty struct, `struct{}`, offers surprisingly practical applications despite lacking fields. It serves effectively as a semaphore or lock in concurrency patterns, often paired with channels to manage access without memory overhead. Developers also leverage it as a memory-efficient placeholder, particularly as map values when only keys are relevant, or to signify a struct's adherence to an interface without requiring specific method implementations. This versatile construct helps optimize memory usage and enhance code clarity in various Go programming scenarios.

在Go语言中,空结构体struct{}是一个没有字段的结构体,看起来似乎没什么用,但实际上,它在某些情况下非常有用,可以成为代码中简单高效的解决方案。

作为信号量或锁

由于空结构体没有字段,因此可以方便地用于实现一些并发控制功能,例如互斥锁、读写锁。我们可以使用chan struct{}实现一个无缓冲通道来控制并发访问。

package main

import (
    "fmt"
    "sync"
)

func main() {
    var wg sync.WaitGroup
    var mu sync.Mutex
    c := make(chan struct{}, 1)

    for i := 0; i < 10; i++ {
        wg.Add(1)
        go func(i int) {
            c <- struct{}{} // 获取锁
            defer func() {
                <-c // 释放锁
                wg.Done()
            }()

            mu.Lock()
            defer mu.Unlock()
            fmt.Printf("goroutine %d: hello\n", i)
        }(i)
    }

    wg.Wait()
}

在上面的代码中,我们使用空结构体struct{}表示信号量。当一个goroutine获取锁时,它将一个空结构体发送到通道中,以表示它已获取锁。执行完毕后,它从通道中接收一个空结构体以释放锁。

占位符

在某些情况下,我们需要声明一个变量或参数,但实际上并不需要使用它。在这种情况下,我们可以使用空结构体作为占位符以避免浪费内存。例如,我们可以使用map[string]struct{}表示键值对的集合,其中空结构体可以用于表示我们只需要键而不需要值的情况。

package main

import "fmt"

func main() {
    m := map[string]struct{}{
        "apple":   {},
        "banana":  {},
        "cherry":  {},
        "durian":  {},
        "elder":   {},
        "fig":     {},
        "grape":   {},
        "honeydew":{},
    }

    for k, _ := range m {
        fmt.Println(k)
    }
}

在上面的代码中,我们使用空结构体作为map[string]struct{}的值,以表示我们只需要键而不需要值。这可以避免浪费内存并提高代码的可读性。

接口实现

在Go语言中,接口是通过实现一组方法来定义的。如果一个结构体没有任何方法需要实现,但需要实现一个接口,则可以使用空结构体作为占位符来表示该结构体实现了该接口。

package main

import "fmt"

type myInterface interface{}

type myStruct struct{}

func (ms myStruct) String() string {
    return "myStruct"
}

func main() {
    var i myInterface = myStruct{}
    fmt.Println(i)
}

在上面的代码中,我们定义了一个空接口myInterface和一个带有String()方法的结构体myStruct,该方法返回myStruct。然后,我们通过将myStruct{}赋值给接口变量i来实现myInterface,使myStruct成为实现myInterface的类型。

在这个例子中,由于myInterface是一个空接口,没有任何方法,因此myStruct作为myInterface的实现不需要实现任何方法。但是,由于myStruct实现了fmt.Stringer接口的String()方法,我们可以使用fmt.Println打印i的值,并获得myStruct的字符串表示。

总而言之,Go语言的空结构体struct{}是一个简单高效的解决方案,在某些情况下非常有用。它可以用作信号量或锁、占位符以及实现某些接口的占位符。此外,使用空结构体可以避免浪费内存并提高代码的可读性。

GOLANG EMPTY STRUCT

  RELATED

  COMMENTS

2
Anonymous
Mar 19, 2024 at 12:06 pm

The first code snippet is giving a deadlock error

Ke Pi
Apr 5, 2024 at 11:54 pm

thank u for pointing it out. have fixed it