Golang中是否可以在结构体中声明常量?

Golang中是否可以在结构体中声明常量? 大家好

如何在结构体中使用常量?

type game struct {
    constants.GAME_ID int
}

我无法在结构体中声明常量,请帮忙。

提前感谢

11 回复

感谢回复

更多关于Golang中是否可以在结构体中声明常量?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


好的,感谢各位的回复

Go 不支持结构体中的常量。

那么你有解决这个问题的方法吗?

我不太清楚你实际想要实现什么。你的目标是什么?了解这一点后,你或许能得到一些建议。

谢谢,这很好但还不够,我认为这种不灵活的结构并不好。

这令人担忧 😞

您可以定义自定义常量类型并实现 Valuer 和 Scanner 接口来定义它们如何从数据库存储和检索。如果选择这种方式,您可能还需要实现 MarshalerUnmarshaler 接口。

如果结构体需要描述要选择的字段,可以查看 https://github.com/jmoiron/sqlx,它在标准库基础上提供了一些实用的快捷方式。您可能还希望将选择操作设为类型本身的方法,这样定义就能靠近结构体定义。

在同一段代码中,无法通过常量来命名结构体字段,除非使用代码生成或(可能)反射。在您完全熟悉 Go 语言的所有方面之前,请不要尝试这种方法,即使到那时也请确保这确实是个好主意。

我的常量文件:

const (
    C_GAME_ID   = "game_id"
    C_GAME_NAME = "game_name"
    C_THUMB_URL = "thumb_url"
)

我的结构体:

type GameO struct {
	GameId       string    `json:"game_id,omitempty"`
	GameName     string    `json:"game_name,omitempty"`
	ThumbUrl     string    `json:"thumb_url,omitempty"`
}

这是数据库查询游标:

...
gameRows := sql.Query("SELECT " + C_GAME_ID + "," + C_GAME_NAME + "," + C_THUMB_URL + " FROM games;")
...
var game_id, game_name, thumb_url
for gameRows.next() {
err = gameRows.Scan( &game_id, &game_name, &thumb_url)
game := structs.GameO {
  GameId: game_id,
  GameName: game_name,
  ThumbUrl: thumb_url
  ...
}
...

我想用常量替换上述代码中的实际值

假设 constants.GAME_ID 的值为 1,那么这种语法:

type game struct {
    constants.GAME_ID int
}

实际上会解析为:

type game struct {
    1 int
}

这是一种无效的语法,同时也缺乏语义含义。

如果希望为每个 game 变量分配游戏 ID,可以在结构体中添加非导出字段,并提供一个返回 ID 值的方法。这样,包外部的代码可以通过该方法读取 ID,但无法直接访问变量,因此也无法修改它。

以下代码展示了这一概念:

package games

import (
	"fmt"
)

const (
	GAME_ID1 = 12345	
        GAME_ID2 = 67890
)

type Game struct {
	id int
}

func (g Game) Id() int {
	return g.id
}
package main

import "path/to/games"

func main() {
	game1 := games.Game{
		id: GAME_ID1,
	}
	fmt.Println("Game ID:", game1.Id())

        // 以下代码无法编译,因为 id 是非导出字段:
        game1.id = 67890
}

简化版代码的 Playground 链接(不包含包)

在Go语言中,结构体字段不能声明为常量。结构体字段本质上是实例变量,每个结构体实例可以拥有不同的值,而常量是编译时确定的不可变值,与实例无关。不过,你可以通过以下几种方式实现类似的功能:

1. 使用未导出字段和常量方法

通过将字段设为未导出(小写字母开头),并提供一个基于常量的getter方法,来模拟常量行为。示例:

type Game struct {
    gameID int // 未导出字段
}

// 常量值
const DefaultGameID = 1001

// 构造函数,设置默认常量值
func NewGame() *Game {
    return &Game{gameID: DefaultGameID}
}

// Getter方法,返回常量值
func (g *Game) GetGameID() int {
    return g.gameID
}

使用方式:

func main() {
    g := NewGame()
    fmt.Println(g.GetGameID()) // 输出: 1001
}

2. 使用嵌入类型和常量

通过嵌入一个包含常量的类型,但注意常量本身不能是结构体字段。示例:

type Constants struct {
    // 无法直接在这里声明常量字段
}

func (c Constants) GameID() int {
    return 1001 // 返回常量值
}

type Game struct {
    Constants // 嵌入Constants类型
    PlayerName string
}

使用方式:

func main() {
    g := Game{PlayerName: "Alice"}
    fmt.Println(g.GameID()) // 输出: 1001
}

3. 直接使用包级常量

如果常量是全局的,不依赖于结构体实例,直接在包级别声明常量:

const GAME_ID = 1001

type Game struct {
    PlayerName string
    // 其他字段...
}

使用方式:

func main() {
    fmt.Println(GAME_ID) // 直接使用常量
}

4. 使用接口和常量组合(高级用法)

通过接口返回常量值,但结构体字段仍不能是常量:

type ConstantsProvider interface {
    GameID() int
}

type DefaultConstants struct{}

func (d DefaultConstants) GameID() int {
    return 1001
}

type Game struct {
    ConstantsProvider
    PlayerName string
}

func NewGame() *Game {
    return &Game{
        ConstantsProvider: DefaultConstants{},
        PlayerName:        "Bob",
    }
}

使用方式:

func main() {
    g := NewGame()
    fmt.Println(g.GameID()) // 输出: 1001
}

总结:Go语言不允许在结构体中声明常量字段。上述方法提供了替代方案,根据你的具体需求选择合适的方式。如果常量是实例无关的,推荐使用包级常量;如果需要与结构体关联,使用getter方法或嵌入类型。

回到顶部