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 函数中不存在?porthost 是包变量。我期望 init 函数在 main 函数之前执行。


更多关于Golang中为什么这种方式不生效?的实战教程也可以访问 https://www.itying.com/category-94-b0.html

4 回复

已解决。问题在于重新创建变量以及未使用类型断言。

更多关于Golang中为什么这种方式不生效?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


init 函数中的 hostport 使用 := 进行初始化,这会导致它们遮蔽包级别的变量,只需改用常规赋值(=)即可。

你在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 函数中声明的 porthost 变量是局部变量,而不是包级变量。在 Go 中,init 函数确实会在 main 函数之前执行,但局部变量的作用域仅限于声明它们的函数内部。

要解决这个问题,你需要将 porthost 声明为包级变量,这样它们就可以在同一个包的不同函数中共享。

以下是修正后的代码示例:

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

关键修改点:

  1. 在包级别声明 porthost 变量
  2. init 函数中为这些包级变量赋值
  3. main 函数中可以直接访问这些包级变量
  4. 由于 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))
}

这样代码会更简洁且类型安全。

回到顶部