Golang中的构造函数实现方法

Golang中的构造函数实现方法 在C语言中,以下语法用于函数名前,以便在main函数之前或库加载时执行: attribute((constructor))

在Go语言中的语法是什么? Go二进制文件包含一个在main之前调用的init函数。但对于Go插件或共享Go库,init函数不会被调用。是否有其他函数/事件(属于插件/共享Go库)在插件/库加载时被调用?

8 回复

Go 没有构造函数。值使用其零值进行初始化。如果零值不够用,那么惯例是命名一个创建 T 的函数为 NewT。

更多关于Golang中的构造函数实现方法的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


那么goplugin/shared-go-library中的init函数呢?在加载时,goplugin/shared-go-library中是否有任何函数会被调用?

关于我错误地认为 init() 仍然更受青睐……抱歉提供了错误信息。 我也没意识到您的用例是关于插件的,我想这个问题在 Stack Overflow 上已经得到了解答。

顺便说一句,我绝无任何挑衅之意!我只是真的很好奇。另外,在那个问题中,他们确实提到 init 可能被过度使用,文档应该涵盖那些习惯性使用它的特定用例。

创建了一个插件(testplug.so)。创建了一个Go应用程序并使用了插件(plugin.open)。testplug.so是不同的代码。当这个插件被加载时,是否有任何方法可以告知插件已被加载?如果我想在调用插件的任何函数之前初始化一些变量,那么我可以在插件加载时完成这个操作。

插件有一个缺点,即不能跨不同的Go版本/子版本使用。 在这种情况下可以使用共享库。我使用“go install”创建了一个共享库。当共享库成功加载时,是否有任何方法会被调用?

如果你要使用 init() 函数,那么你应该将每个类放到自己的包中。

但是:

  • 每个构造函数/init() 都会在 main() 之前运行
  • 甚至 Go 核心团队也表示 init 是一个错误,不应该被使用。

我犯了一个错误,试图从其他面向对象语言中实现功能,这是个错误。 我本应该努力忘记旧的概念,并按照其他 Go 代码的风格和感觉来写……那样本可以为我节省大量时间,并避免架构上的错误。

关于 goplugin/shared-go-library 中的 init 函数呢?在 goplugin/shared-go-library 中是否有在加载期间被调用的函数?

如果导入共享库,其 init 函数会被调用。更多细节请参阅 Stack Overflow 上的这个问题。或许你可以贴出一些实际有问题的代码,或者具体描述一下你正试图解决的问题?

甚至 Go 核心团队都说 init 是个错误,不应该使用。

@apmattil 你能详细说明一下吗?我不知道核心团队有任何不建议使用 init 的指导原则。另请参阅 这个提议移除 init 的提案 以及核心团队对其的接受情况。

在Go语言中,可以通过init函数实现类似的功能,但需要注意插件场景的特殊性。以下是具体实现方法:

1. 标准包中的init函数

package mypackage

import "fmt"

// init函数在包被导入时自动执行
func init() {
    fmt.Println("包初始化 - 在main之前执行")
}

// 其他函数
func MyFunction() {
    fmt.Println("普通函数")
}

2. 插件(plugin)中的初始化

对于Go插件,确实存在init函数不被调用的问题。可以通过导出初始化函数手动调用:

plugin.go:

package main

import "C"
import "fmt"

var initialized bool

// 导出给C调用的初始化函数
//export InitializePlugin
func InitializePlugin() {
    if !initialized {
        fmt.Println("插件初始化")
        initialized = true
    }
}

// 插件业务函数
//export PluginFunction
func PluginFunction() {
    fmt.Println("插件功能执行")
}

func init() {
    // 注意:插件中的init函数在动态加载时不会自动执行
    fmt.Println("这个init函数在插件加载时不会自动执行")
}

func main() {
    // 插件必须包含main函数,但不会被执行
}

3. 使用sync.Once确保单次初始化

package mylib

import (
    "fmt"
    "sync"
)

var (
    once sync.Once
)

// 导出初始化函数
func Initialize() {
    once.Do(func() {
        fmt.Println("库初始化(仅执行一次)")
        // 初始化代码
    })
}

// 业务函数
func LibraryFunction() {
    Initialize() // 确保先初始化
    fmt.Println("执行业务逻辑")
}

4. 构建标签控制初始化

// +build !plugin

package mypackage

func init() {
    // 这个init函数在构建插件时不会包含
    fmt.Println("标准包初始化")
}

5. 完整的插件使用示例

主程序:

package main

import (
    "fmt"
    "plugin"
)

func main() {
    // 加载插件
    p, err := plugin.Open("myplugin.so")
    if err != nil {
        panic(err)
    }
    
    // 查找并调用初始化函数
    initFunc, err := p.Lookup("InitializePlugin")
    if err == nil {
        initFunc.(func())()
    }
    
    // 调用插件功能
    pluginFunc, err := p.Lookup("PluginFunction")
    if err == nil {
        pluginFunc.(func())()
    }
}

Go插件的init函数确实不会在动态加载时自动执行,这是与标准包导入的主要区别。需要通过导出显式的初始化函数来手动控制初始化过程。

回到顶部