提问人:Grant 提问时间:9/4/2022 更新时间:9/5/2022 访问量:335
将结构指针传递给采用接口指针的函数
Passing Struct Pointers to Functions That Take Interface Pointers
问:
我正在尝试理解将接口指针作为参数的函数的问题,但仍然不能完全理解这个问题,所以如果这是一个重复的问题,请道歉。虽然我理解人们普遍认为通常不需要指向接口的指针,但我觉得我实际上处于实现它们会很有用的情况。不过,如果不是这种情况,请随时告诉我
我计划从多个安全交易所获取 OHLC 数据。我目前正在为加密货币交易所编写机器人,但也计划为外汇和证券交易所/经纪商编写机器人。目标是让每个交换的 OHLC 响应写入结构体。OHLC的响应在交换之间通常不相同,因此这可能会产生一个问题,我希望通过接口来解决OHLCVals
每个机器人都有自己的结构(这是一个示例),用于实现接口的方法。此结构包含有关 OHLC 订阅的一些“元数据”,这些“元数据”通常是特定于 Exchange 的。该列表实际上将每个蜡烛的 OHLC 数据保存在单独的节点中,每个节点的字段也是一个接口。由于每个交易所都有自己的结构,我相信我可以解决结构中的字段作为接口的大多数问题。因为我需要在新数据进入时更新地图中的列表,所以我认为我需要使用指针地图才能进行这些更新。OHLCResponseHolder
KrakenOHLCResponseHolder
OhlcResponseHolder
Data
OHLCResponseHolder
Vals
OHLCVals
OhlcResponseHolder
我相信在这种情况下,使用接口指针可能是最好的解决方案,因为我唯一能想到的其他事情就是使用泛型。如果我没记错的话,泛型不能与地图一起使用。即使它们能够与地图一起使用,它也可能变得非常乏味,因为我计划支持许多交换(希望是 10-20 个),这将导致具有许多可接受的数据类型和许多非边缘情况的通用函数来测试
由于我的函数用例将指向接口的指针排除在外,因此我在将结构指针传递给采用接口指针的函数时遇到了一些麻烦。以下是我目前编码的接口和结构:
type Candle interface {
GetCandle() Candle
GetStartTime() UnixTime
GetEndTime() UnixTime
GetHigh() decimal.Decimal
SetHigh(num decimal.Decimal)
GetLow() decimal.Decimal
SetLow(num decimal.Decimal)
GetClose() decimal.Decimal
SetClose(num decimal.Decimal)
GetVWAP() decimal.Decimal
SetVWAP(num decimal.Decimal)
GetVolume() decimal.Decimal
SetVolume(num decimal.Decimal)
GetCount() int
SetCount(num int)
}
type Node struct {
Data Candle
Next *Node
}
type List interface {
GetList() List
AddToEnd(n *Node)
Print(locker *sync.RWMutex)
IsEmpty() bool
GetLast() *Node
}
type list struct {
Head *Node
Last *Node
Length uint
}
func NewList(head *Node, last *Node, length uint) *list {
return &list{Head: head, Last: last, Length: length}
}
func (l *list) GetList() List {
return l
}
func (l *list) AddToEnd(n *Node) {
if l.Head == nil {
l.Head = n
l.Last = n
l.Length++
return
}
tmp := l.Last
tmp.Next = n
l.Last = n
l.Length++
}
func (l list) Print(locker *sync.RWMutex) {
locker.RLock()
tmp := l.Head
for tmp != nil {
fmt.Println(string("\033[34m"), tmp.Data, string("\033[0m"))
tmp = tmp.Next
}
locker.RUnlock()
fmt.Println()
}
func (l list) IsEmpty() bool {
return l.Length == 0
}
func (l *list) GetLast() *Node {
return l.Last
}
type OhlcResponseHolder interface {
GetChannelID() int
GetList() *List
GetInterval() int64
}
type KrakenOHLCResponseHolder struct {
ChannelID int
Interval int64
ChannelName string
Pair string
List shared_types.List
}
func (o KrakenOHLCResponseHolder) GetChannelID() int {
return o.ChannelID
}
func (o *KrakenOHLCResponseHolder) GetList() *shared_types.List {
return &o.List
}
func (o KrakenOHLCResponseHolder) GetInterval() int64 {
return o.Interval
}
type OHLCValHolder interface {
Set(key int, data *OhlcResponseHolder)
RLock()
RUnlock()
Lock()
Unlock()
GetVals() map[int]*OhlcResponseHolder
GetMutex() *sync.RWMutex
}
type OHLCVals struct {
Vals map[int]*shared_types.OhlcResponseHolder
Mutex sync.RWMutex
}
func (ohlcVals *OHLCVals) Set(key int, data *shared_types.OhlcResponseHolder) {
if ohlcVals.Vals == nil {
ohlcVals.Vals = make(map[int]*shared_types.OhlcResponseHolder)
}
ohlcVals.Vals[key] = data
}
func (ohlcVals *OHLCVals) RLock() {
ohlcVals.Mutex.RLock()
}
func (ohlcVals *OHLCVals) RUnlock() {
ohlcVals.Mutex.RUnlock()
}
func (ohlcVals *OHLCVals) Lock() {
ohlcVals.Mutex.Lock()
}
func (ohlcVals *OHLCVals) Unlock() {
ohlcVals.Mutex.Unlock()
}
func (ohlcVals *OHLCVals) GetVals() map[int]*shared_types.OhlcResponseHolder {
return ohlcVals.Vals
}
func (ohlcVals *OHLCVals) GetMutex() *sync.RWMutex {
return &ohlcVals.Mutex
}
这是使用代码的上下文:
func HandleOHLCResponse(v *types.OHLCResponse, ohlcMap *shared_types.OHLCValHolder) {
(*ohlcMap).RLock()
if subID, found := (*ohlcMap).GetVals()[v.ChannelID]; found { // if channelID already exists in the map, then...
// stuff
fmt.Println(2+2)
} else { // if the channel id cannot be found in the map
interval, _ := strconv.ParseInt(v.ChannelName[len(v.ChannelName)-1:], 10, 64)
v.OHLCArray.StartTime.Time = v.OHLCArray.EndTime.Add(-time.Minute * time.Duration(interval))
node := shared_types.Node{Data: &v.OHLCArray, Next: nil}
tmp := types.KrakenOHLCResponseHolder{ChannelID: v.ChannelID, ChannelName: v.ChannelName, Pair: v.Pair, Interval: interval, List: shared_types.NewList(&node, &node, 1)}
(*ohlcMap).RUnlock()
(*ohlcMap).Lock()
(*ohlcMap).Set(tmp.ChannelID, &tmp)
(*ohlcMap).Unlock()
}
}
这是我作为参数传递给时遇到的错误:cannot use &tmp(类型为*“bruit/bruit/clients/kraken/types”的值。KrakenOHLCResponseHolder)作为*shared_types。参数中的 OhlcResponseHolder 值 (*ohlcMap)。设置: *“bruit/bruit/clients/kraken/types”。KrakenOHLCResponseHolder 不实现 *shared_types。OhlcResponseHolder(类型 *shared_types。OhlcResponseHolder 是指向接口的指针,而不是接口)&tmp
(*ohlcMap).Set(tmp.ChannelID, &tmp)
将不胜感激
答:
类型是指向接口类型的指针。*types.OhlcResponseHolder
不能将值作为第二个参数传递给 类型:&tmp
Set
*types.OhlcResponseHolder
- 的基础类型是
&tmp
KrakenOHLCResponseHolder
- 的基础类型是
*types.OhlcResponseHolder
types.OhlcResponseHolder
- 这些类型不完全相同(命名类型仅与它们本身相同)
- 因此不能分配给
&tmp
*types.OhlcResponseHolder
- 因此不能转换为(参见第一条规则:x 可分配给 T
&tmp
*types.OhlcResponseHolder
)
如果您使用中间变量,您仍然可以使用:tmp
var h_tmp types.OhlcResponseHolder = tmp
(*ohlcMap).Set(tmp.ChannelID, &h_tmp)
这将起作用,因为 的底层类型是 并且它与函数的第二个参数的类型相同。&h_tmp
types.OhlcResponseHolder
Set
下面是一个简化的示例:https://go.dev/play/p/zCAe56jg_re
这个 recipie 的问题是它没有实现 - 该方法是为指针接收器定义的。KrakenOHLCResponseHolder
OhlcResponseHolder
GetList
评论
上一个:如何更改函数内数组的大小?
下一个:带指针的结构 [已关闭]
评论
temp
Set
tmp := shared_types.OhlcResponseHolder(types.KrakenOHLCResponseHolder{ ... })
ohlcMap