Golang中为什么这种方式不生效?
Golang中为什么这种方式不生效? 在 main.go 文件中我有:
func init() {
...
port := viper.Get("port")
host := viper.Get("host")
if port == nil || host == nil {
log.Fatal("configuration数据未找到")
}
fmt.Println(fmt.Sprintf("%s:%d", host, port)) // 这里输出 127.0.0.1:8080
}
func main() {
...
fmt.Println(fmt.Sprintf("%s:%d", host, port)) // 但这里输出 ':'
log.Fatal(http.ListenAndServe(host+":"+port), r))
}
为什么这些 init 函数中的数据在 main 函数中不存在?port 和 host 是包变量。我期望 init 函数在 main 函数之前执行。
更多关于Golang中为什么这种方式不生效?的实战教程也可以访问 https://www.itying.com/category-94-b0.html
4 回复
已解决。问题在于重新创建变量以及未使用类型断言。
更多关于Golang中为什么这种方式不生效?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
init 函数中的 host 和 port 使用 := 进行初始化,这会导致它们遮蔽包级别的变量,只需改用常规赋值(=)即可。
你在init()函数内部定义了host和port变量,当这个函数结束时这些变量就会消失。你需要在外部块中声明它们,例如:
var port string
var host string
func init() {
...
port = viper.Get("port")
host = viper.Get("host")
if port == nil || host == nil {
log.Fatal("configuration data not found")
}
fmt.Println(fmt.Sprintf("%s:%d", host, port)) // 这会输出 127.0.0.1:8080
}
问题在于你在 init 函数中声明的 port 和 host 变量是局部变量,而不是包级变量。在 Go 中,init 函数确实会在 main 函数之前执行,但局部变量的作用域仅限于声明它们的函数内部。
要解决这个问题,你需要将 port 和 host 声明为包级变量,这样它们就可以在同一个包的不同函数中共享。
以下是修正后的代码示例:
package main
import (
"fmt"
"log"
"net/http"
"github.com/spf13/viper"
)
// 声明包级变量
var (
port interface{}
host interface{}
)
func init() {
// 现在赋值给包级变量
port = viper.Get("port")
host = viper.Get("host")
if port == nil || host == nil {
log.Fatal("configuration数据未找到")
}
fmt.Printf("%s:%v\n", host, port) // 输出 127.0.0.1:8080
}
func main() {
fmt.Printf("%s:%v\n", host, port) // 现在会正确输出 127.0.0.1:8080
// 注意:需要将接口类型转换为字符串
portStr := fmt.Sprintf("%v", port)
hostStr := fmt.Sprintf("%v", host)
log.Fatal(http.ListenAndServe(hostStr+":"+portStr, nil))
}
关键修改点:
- 在包级别声明
port和host变量 - 在
init函数中为这些包级变量赋值 - 在
main函数中可以直接访问这些包级变量 - 由于
viper.Get()返回interface{}类型,在使用前需要转换为字符串
另一种更好的做法是使用类型断言或直接使用 viper 的字符串获取方法:
var (
port string
host string
)
func init() {
port = viper.GetString("port")
host = viper.GetString("host")
if port == "" || host == "" {
log.Fatal("configuration数据未找到")
}
fmt.Printf("%s:%s\n", host, port)
}
func main() {
fmt.Printf("%s:%s\n", host, port)
log.Fatal(http.ListenAndServe(host+":"+port, nil))
}
这样代码会更简洁且类型安全。

