考虑到Go中的以下软件包,是否可以阻止使用Bar
直接初始化Bar{..}
而不从软件包中解除Bar
?
包bar
:
package bar
import ()
type Bar struct {
A string
B string
}
func NewBar(baz string) Bar{
return Bar{A:baz, B:baz+baz}
}
包main
:
package main
import (
"fmt"
"./bar"
)
func main() {
x := bar.NewBar("sad") //all bars should be created with this
y := bar.Bar{A: "fadss"} //and this should be disallowed
bzzBar(x)
bzzBar(y)
}
func bzzBar(bzz bar.Bar) { //but I can't do 'Bar -> bar' because I want to use the type
fmt.Println(bzz)
}
我的直觉是说无法做到这一点,所以这也是一个有效的答案。
答案 0 :(得分:4)
您可以将所有Bar
字段取消导出,并为其提供getter和setter。这样,包用户仍然可以做一些愚蠢的事情,比如
a := Bar{}
b := Bar{"foo"}
既不是,也没有用(虽然前者可用于创建类似于Bar
的空&bytes.Buffer{}
。)
答案 1 :(得分:4)
无法阻止Bar{}
或Bar{A: "foo"}
。
要以您希望的方式控制结构,您可以返回一个接口,而不是导出结构本身。
给出的例子:
package bar
type Bar interface{
A() string
B() string
// if you need setters
SetA(string)
SetB(string)
}
type bar struct {
a string
b string
}
func (b *bar) A() string { return b.a }
func (b *bar) B() string { return b.b }
func (b *bar) SetA(val string) { b.a = val }
func (b *bar) SetB(val string) { b.b = val }
func NewBar(baz string) Bar {
return &bar{a:baz, b:baz+baz}
}
答案 2 :(得分:4)
Go标准库中使用的习语是:
package bar
package bar
import (
"fmt"
)
type Bar struct {
a string
b string
}
func New(baz string) *Bar {
return &Bar{a: baz, b: baz + baz}
}
func (b *Bar) BzzBar() {
fmt.Println(*b)
}
package main
package main
import (
"bar"
)
func main() {
x := bar.New("sad") //all bars should be created with this
x.BzzBar()
// error: unknown bar.Bar field 'A' in struct literal
// y := bar.Bar{A: "fadss"} //and this should be disallowed
}
输出:
{sad sadsad}
附录:
The Go Programming Language Specification
当分配内存来存储值时,通过a 声明或调用make或new,并且没有明确的初始化 如果提供,则为存储器提供默认初始化。每 将此类值的元素设置为其类型的零值:false 对于布尔值,0表示整数,0.0表示浮点数,""对于字符串,没有 用于指针,函数,接口,切片,通道和映射。这个 初始化是递归完成的,所以例如每个元素 如果没有指定值,结构数组将使其字段归零。
Go标准库中使用的另一个习惯用法是使零值有意义。例如,如果new
尚未明确初始化,则其默认值为false
。
type Bar struct {
new bool
a string
b string
}
例如,
package bar
import (
"fmt"
)
type Bar struct {
new bool
a string
b string
}
func New(baz string) *Bar {
return &Bar{new: true, a: baz, b: baz + baz}
}
func (b *Bar) notnew() {
if b == nil || !b.new {
panic("bar.Bar not bar.New")
}
}
func (b *Bar) Bzz() {
b.notnew()
fmt.Println(*b)
}
package main
import (
"bar"
)
func main() {
x := bar.New("sad") //all bars should be created with this
x.Bzz()
// error: unknown bar.Bar field 'A' in struct literal
// y := bar.Bar{A: "fadss"} //and this should be disallowed
// var b bar.Bar
// panic: bar.Bar not bar.New
// b.Bzz()
// var b = bar.Bar{}
// panic: bar.Bar not bar.New
// b.Bzz()
// var bp *bar.Bar
// panic: bar.Bar not bar.New
// bp.Bzz()
// var bp = new(bar.Bar)
// panic: bar.Bar not bar.New
// bp.Bzz()
}
输出:
{true sad sadsad}
答案 3 :(得分:1)
如果您提供A
功能,则应该无法导出B
和String()
:
type Bar struct {
a string
b string
}
func NewBar(baz string) Bar{
return Bar{a:baz, b:baz+baz}
}
func (Bar) String() string {
return a + " " b
}