Go to: prohibit direct structuring

Given the following packages in Go, is it possible to prevent direct initialization Barusing Bar{..}without removing from the package Bar?

package Bar:

package bar

import ()

type Bar struct {
    A string
    B string
}

func NewBar(baz string) Bar{
    return Bar{A:baz, B:baz+baz}
}

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

The gut feeling says this cannot be done, so this is also the right answer.

+4
source share
4 answers

The idiom used in the standard Go library:

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
}

Conclusion:

{sad sadsad}

ADDITION:

Go programming language specification

Zero value

, make , , . : false booleans, 0 , 0.0 float, "" nil , , , , . , , , , .

, 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

Bar . , ,

a := Bar{}
b := Bar{"foo"}

( Bar, &bytes.Buffer{}).

+4

Unable to prevent Bar{}or Bar{A: "foo"}.

To manage the structure the way you want, you can return the interface and not export the structure itself.

Example:

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
source

You should be able to not export Aand B, if you provide a function 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
}
+1
source

All Articles