英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论