如何跟踪类型的实例数量?

huangapple go评论85阅读模式
英文:

How to keep track of the count of instances of a type?

问题

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

我尝试在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
}

这个方法只能实现一半,因为我无法通过析构函数来递减计数器。

我能否以某种方式模拟对象的销毁?
如何正确地跟踪实例数量?

英文:

In object oriented languages I use class variables to track how many instances are currently spawned by incrementing on construction and decrementing on destruction.

I try to implement similar behaviour in 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
}

and that works half way as I can not decrement the counter via a destructor.

Can I somehow mimic object destruction?
How would I keep track of instance count correctly?

答案1

得分: 9

你可以像这样使用runtime.SetFinalizer。在这里查看playground版本。

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

请注意,关于Finalizers的文档中有一些需要注意的地方:

x的finalizer被安排在x变得不可达之后的某个任意时间运行。不能保证finalizer会在程序退出之前运行,因此它们通常只在长时间运行的程序中用于释放与对象关联的非内存资源。

英文:

You can use runtime.SetFinalizer like this. See here for playground version.

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)
}

This prints

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

Note this from the docs for gotchas with Finalizers

> The finalizer for x is scheduled to run at some arbitrary time after x
> becomes unreachable. There is no guarantee that finalizers will run
> before a program exits, so typically they are useful only for
> releasing non-memory resources associated with an object during a
> long-running program.

答案2

得分: 5

关于finalizers,golang-nuts上有一个讨论

目前,

  • 没有finalizer函数(编辑:没有可靠的finalizer函数,正如Nick向我展示的)
  • 垃圾回收器不使用也不维护任何引用计数

因此,您必须自己管理实例计数。

通常,您不会有实例自己存在的情况,因此对于许多实际用途(不包括复杂且难以理解的程序的分析),您可以使用defer来跟踪变量的生命周期结束。我不会假装这真的可以替代finalizers,但它简单且通常足够。

英文:

There was a discussion on golang-nuts about finalizers.

For now,

  • there is no finalizer function (edit : no reliable finalizer function, as was shown to me by Nick)
  • the GC doesn't use and doesn't maintain any reference count

So you have to manage your instance count yourself.

Usually, you don't have instances living on themselves, so for many practical uses (not including the profiling of a complex and hard to understand program), you can use defer to track the end of life of your variables. I won't pretend this really replaces finalizers but it's simple and often sufficient.

huangapple
  • 本文由 发表于 2012年11月9日 21:26:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/13308955.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定