pointers - go 中的引用 - 属性不会改变

标签 pointers go reference slice

我很难理解 go 中的引用是如何工作的。我想编写一个非常简单的内存中发布-订阅机制。这是代码:

package sockets

import (
    "fmt"

    "github.com/gorilla/websocket"
)

type hubSingleton struct {
    Clients map[string][]*websocket.Conn
}

var instance *hubSingleton

func Hub() *hubSingleton {

    if instance == nil {
        fmt.Println("New instance created")
        instance = &hubSingleton{}
    }
    instance.Clients = make(map[string][]*websocket.Conn, 6)
    return instance
}

func (hub *hubSingleton) Subscribe(channel string, socket *websocket.Conn) error {
    if _, ok := hub.Clients[channel]; !ok {
        hub.Clients[channel] = make([]*websocket.Conn, 0)
    }
    hub.Clients[channel] = append(hub.Clients[channel], socket)

    fmt.Println("Subscribe: ", hub.Clients)
    return nil
}

func (hub *hubSingleton) Publish(channel string, message interface{}) {
    fmt.Println("Publish: ", hub.Clients)

    if _, ok := hub.Clients[channel]; !ok {
        return
    }
    for i := 0; i < len(hub.Clients[channel]); i++ {
        conn := hub.Clients[channel][i]
        conn.WriteJSON(Message{status: "ok", content: message})
    }
}

问题是似乎每次我调用 Hub().Publish() 或 Hub().Subscribe() 时都会创建一个新的 hubSingleton.Client。好吧,我不确定会发生什么,但这是运行程序的输出:

Publish:  map[]
Subscribe:  map[chan:[0xc820170000]]
Publish:  map[]
Subscribe:  map[chan:[0xc82008ac80]]
Publish:  map[]
Publish:  map[]
Publish:  map[]
Subscribe:  map[chan:[0xc820170140]]
Publish:  map[]

每次我调用 Hub() 时,添加到 map 的订阅者都会消失。 我该怎么做才能在调用之间保留 map 中的更改?

最佳答案

Hub 函数在每次调用时都会创建一个新的客户端映射。将函数更改为:

func Hub() *hubSingleton {
  if instance == nil {
    fmt.Println("New instance created")
    instance = &hubSingleton{}
    instance.Clients = make(map[string][]*websocket.Conn, 6)
  }
  return instance
}

如果对 Hub 的第一次调用来自请求处理程序,则 instance 上存在数据竞争。使用锁来固定比赛:

var (
  instance *hubSingleton
  mu sync.Mutex
)

func Hub() *hubSingleton {
  mu.Lock()
  defer mu.Unlock()
  if instance == nil {
    fmt.Println("New instance created")
    instance = &hubSingleton{}
    instance.Clients = make(map[string][]*websocket.Conn, 6)
  }
  return instance
}

一个更简单的方法是在使用前初始化一次实例:

var instance *hubSingleton

func newHub() *hubSingleton {
   return &hubSingleton{Clients:  make(map[string][]*websocket.Conn, 6)}
}

func main() {
   instance = newHub()
   ...
}

如果处理程序同时调用PublishSubscribe,则Publish 中的Clients 上存在数据竞争和订阅

关于pointers - go 中的引用 - 属性不会改变,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39640284/

相关文章:

c++ - C/C++ - 指针传递给 DLL 中的函数

hash - Golang 使用 MD5 编码字符串 UTF16 little endian 和哈希

go - 使用 go 模块后,IDE 无法跟踪我的代码

javascript - 如果我忽略对象在层次结构中的深度,如何为对象的字段赋值?

java - 构造父类和子类引用

c++ - 使用指针显式调用指向对象的析构函数后,指针持有什么样的值?

c++ - 尝试引用已删除函数的唯一指针

c++ - Const 正确性导致指针容器出现问题?

docker - "cannot find module providing for package"在 go 中

c++ - 下标运算符重载 : returning reference problems