Go语言中的常量结构体

72

为什么我不能创建常量结构体?

const FEED_TO_INSERT = quzx.RssFeed{ 0,
                    "",
                    "desc",
                    "www.some-site.com",
                    "upd_url",
                    "img_title",
                    "img_url",
                    0,
                    0,
                    0,
                    0,
                    0,
                    100,
                    "alt_name",
                    1,
                    1,
                    1,
                    "test",
                    100,
                    100,
                    0 }
.\rss_test.go:32:常量初始化器quzx.RssFeed字面值不是常量。

1
你能否添加已回答问题的链接?这样可以将其链接回原始问题以避免重复。 - Zhenhua
2
重新打开标记。询问是否可以创建一个常量结构体与询问数组是不同的,即使答案相似。 - Duncan Jones
常量结构体存在潜在的实现问题,用户可能会尝试将值分配给一个常量字段,这可能是他们最初没有实现它的原因。 - SOFe
5个回答

103

因为 Go 不支持结构体常量(强调是我的)

Go 支持布尔常量、字符常量、整数常量、浮点数常量、复数常量和字符串常量。 字符常量、整数常量、浮点数常量和复数常量被统称为数字常量。

阅读更多请查看: https://golang.org/ref/spec#Constants


30
难过。这是一个方便的语言功能。 - Daniel Santos

28
一个好的解决方法是将它包装在一个函数中。
func FEED_TO_INSERT() quzx.RssFeed {
    return quzx.RssFeed{ 0,
                    "",
                    "desc",
                    "www.some-site.com",
                    "upd_url",
                    "img_title",
                    "img_url",
                    0,
                    0,
                    0,
                    0,
                    0,
                    100,
                    "alt_name",
                    1,
                    1,
                    1,
                    "test",
                    100,
                    100,
                    0 }
}
注意:确保函数始终返回新对象(或副本)。

3
通过“始终返回一个新对象”的方式来模拟某些不可变的东西,这些东西不能改变且应该与自身完全相同。听起来很奇怪。 - ceving

21

你应该将它声明为变量。

在 Go 中,你可以在模块作用域内声明和初始化全局变量。

Go 没有任何不可变性的概念。'const' 不是一种防止变量突变或类似情况发生的方法。


5
这是正确的(在Go中的const更接近C中的#define而不是C#中的readonly),但并不能真正解释为什么不能有类似结构体的常量值。它们可能被排除在外(与类似数组和映射的值一样)是为了简化编译器设计。 - kbolino

0
您可以将结构体字段声明为私有的,然后创建 getter 方法。
type ImmutableType struct {
  immutableField string
}

func (p ImmutableType) GetImmutableField() string {
  return p.immutableField
}

如果您这样做,该字段本身将无法在模块外部访问,并变得类似不可变。

然而,

  • 这只能在结构层面上完成,而不能在声明变量时完成
  • 如果您想在模块外部实例化结构体,则还必须创建构造函数,这变得有点混乱,因为构造函数并不是Go中常用的实践。

为了“强制”使用构造函数,您还可以声明自己的结构体为私有,这样它就不能作为复合字面量创建而没有私有字段。

type immutableType struct {
  immutableField string
}

func (p immutableType) GetImmutableField() string {
  return p.immutableField
}

func CreateImmutableType(immutableField string) immutableType {
  return immutableType{
    immutableField: immutableField,
  }
}

TL;DR:Go语言没有不变性作为核心概念,因此实现它需要大量的样板代码。

0
正如所说,Go语言不支持常量结构变量。这是有原因的,编译器无法确保任何结构体(例如包含指针的结构体)的不可变性。解决方案相当简单:只需使用普通变量即可。
type Person struct {
    age int
}

var Luke = Person{10}

你还可以使用匿名结构体。
var Andrew = struct {
    age int
}{
    age: 13,
}

当你将这个变量创建为全局变量时,要小心对待它。另一个建议是使用一个函数来始终返回一个副本,这是另一个极端。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接