8

在面向对象的语言中,我使用类变量来跟踪当前通过构造递增和销毁递减产生的实例数量。

我尝试在 go 中实现类似的行为:

package entity

type Entity struct {
    Name string
}

func New(name string) Entity {
    entity := Entity{name}
    counter++
    return entity
}

var counter int = 0

func (e *Entity) Count() int {
    return counter
}

这工作了一半,因为我不能通过析构函数减少计数器。

我可以以某种方式模仿对象破坏吗?我将如何正确跟踪实例计数?

4

2 回答 2

9

您可以像这样使用runtime.SetFinalizer。有关游乐场版本,请参见此处

package main

import (
    "fmt"
    "runtime"
)

type Entity struct {
    Name string
}

var counter int = 0

func New(name string) Entity {
    entity := Entity{name}
    counter++
    runtime.SetFinalizer(&entity, func(_ *Entity) {
        counter--
    })
    return entity
}

func (e *Entity) Count() int {
    return counter
}

func main() {
    e := New("Sausage")
    fmt.Println("Entities", counter, e)
    e = New("Potato")
    fmt.Println("Entities", counter, e)
    runtime.GC()
    fmt.Println("Entities", counter)
    e = New("Leek")
    fmt.Println("Entities", counter)
    runtime.GC()
    fmt.Println("Entities", counter)
}

这打印

Entities 1 {Sausage}
Entities 2 {Potato}
Entities 0
Entities 1
Entities 0

请从文档中注意这一点,了解带有终结器的陷阱

x 的终结器计划在 x 变得无法访问后的某个任意时间运行。无法保证终结器会在程序退出之前运行,因此它们通常仅用于在长时间运行的程序期间释放与对象关联的非内存资源。

于 2012-11-09T18:52:15.440 回答
5

关于终结器的 golang-nuts有一个讨论。

目前,

  • 没有终结器功能(编辑:没有可靠的终结器功能,正如尼克向我展示的那样)
  • GC 不使用也不维护任何引用计数

所以你必须自己管理你的实例数。

通常,您没有独立存在的实例,因此对于许多实际用途(不包括分析复杂且难以理解的程序),您可以使用它defer来跟踪变量的生命周期结束。我不会假装这真的取代了终结器,但它很简单而且通常就足够了。

于 2012-11-09T13:40:58.793 回答