您的位置 首页 golang

golang 结构体


普通结构体

1.public

type Flower struct {    Name string    Color string    Category string}

外部包可以直接引用和赋值
2.private

type leaf struct {    count int    size int}

外部包不能直接引用
需要定义public函数提供操作,例如

func (l *leaf) SetColor(color string) {    l.color = color}

3.public结构体里面有private

type Flower struct {    Name string    Color string    Category string}

这种情况下,只能通过public的函数或者方法来操作内部的private属性
4.private结构体里面有public属性

type leaf struct {    color string    size int    Count int}

这种也是允许的,例如:

func NewLeaf(color string, size, count int) *leaf{    var l = leaf{color, size, count}    return &l}

在另一个包中引用这些结构体

func main() {    leaf := plant.NewLeaf("green", 5, 10)    fmt.Println(leaf)    leaf.Count = 5    fmt.Println(leaf)}

输出:

&{green 5 10}&{green 5 5}

很少看到这么使用

嵌套结构体

type Leaf struct {    Color string    Size int    Count int}type Flower struct {    Leaf Leaf    Name string    Color string    Category string}

访问方式:

func main() {    f := plant.Flower{}    f.Category = "Roseceae"    f.Name = "Rose"    f.Color = "Red"    f.Leaf.Color = "green"    f.Leaf.Count = 5    f.Leaf.Size = 10    fmt.Println(f)}

这种嵌套,在访问内部结构的成员时,必须显示的指向,如:
f.Leaf.Color

嵌套匿名结构体

type Leaf struct {    Color string    Size int    Count int}type Flower struct {    Leaf    Name string    Color string    Category string}

访问方式:

func main() {    f := plant.Flower{}    f.Category = "Roseceae"    f.Name = "Rose"    f.Color = "Red"    f.Count = 5    f.Size = 10    f.Leaf.Color = "green"    fmt.Println(f)}

如上可以看出,有两种访问方式:
a.直接由外部结构体访问内部结构体成员,跟访问外部结构体内部自己的成员一样

f.Count = 5f.Size = 10

b.外部结构体指向内部结构体,再访问其内部成员

f.Leaf.Color = "green"

注意:在内外结构体有成员名称相同时,如果访问嵌套结构体的成员,必须按照b方式访问,否则是直接访问的外层结构体成员变量。

结构体中嵌套接口

以golang内置的包context为例

type Context interface {    Deadline() (deadline time.Time, ok bool)    Done() <-chan struct{}    Err() error    Value(key interface{}) interface{}}// A canceler is a context type that can be canceled directly. The// implementations are *cancelCtx and *timerCtx.type canceler interface {    cancel(removeFromParent bool, err error)    Done() <-chan struct{}}// A cancelCtx can be canceled. When canceled, it also cancels any children// that implement canceler.type cancelCtx struct {    Context    mu       sync.Mutex            // protects following fields    done     chan struct{}         // created lazily, closed by first cancel call    children map[canceler]struct{} // set to nil by the first cancel call    err      error                 // set to non-nil by the first cancel call}

这种嵌套,可以当成继承来理解,
首先Context接口有四个方法,全部被cancelCtx这个结构体继承了,然后重写了其中三个方法

func (c *cancelCtx) Value(key interface{}) interface{} {    if key == &cancelCtxKey {        return c    }    return c.Context.Value(key)}func (c *cancelCtx) Done() <-chan struct{} {    c.mu.Lock()    if c.done == nil {        c.done = make(chan struct{})    }    d := c.done    c.mu.Unlock()    return d}func (c *cancelCtx) Err() error {    c.mu.Lock()    err := c.err    c.mu.Unlock()    return err}

同时,cancelCtx又实现了canceler这个接口定义的方法,所以cancelCtx又可以当成canceler接口用:

// cancel closes c.done, cancels each of c's children, and, if// removeFromParent is true, removes c from its parent's children.func (c *cancelCtx) cancel(removeFromParent bool, err error) {    //具体实现见源码}func WithCancel(parent Context) (ctx Context, cancel CancelFunc) {    c := newCancelCtx(parent)    propagateCancel(parent, &c)    return &c, func() { c.cancel(true, Canceled) }}// newCancelCtx returns an initialized cancelCtx.func newCancelCtx(parent Context) cancelCtx {    return cancelCtx{Context: parent}}// propagateCancel arranges for child to be canceled when parent is.func propagateCancel(parent Context, child canceler) {    //具体实现见源码}

从WithCancel中可以看到,执行c := newCancelCtx(parent)之后,c其实是cancelCtx类型,再调用propagateCancel时,第二个参数是canceler接口类型,直接取c地址传入,然后&c就当canceler接口用了,最后return时,又将&c当Context接口返回了

Context包代码不多,可以自己研究源码,认识会更深刻。

json/xml结构体

JSON:
Json结构体定义的时候,成员名称和结构体名称必须可导出,即必须以大写开头,如:

type Os struct {    Arch     string    Major    string    Minor    string    Name     string    Platform string    Version  string}

但是,这样在序列化成json字符串的时候,会以成员名称作为json字符串中的名称:

func main() {    linux := Os{        Arch: "x86_64",        Major: "7",        Minor: "7",        Name: "CentOS Linux",        Version: "7.7",    }    js, err := json.Marshal(linux)    if err != nil {        return    }    fmt.Println(string(js))}

输出:

{"Arch":"x86_64","Major":"7","Minor":"7","Name":"CentOS Linux","Platform":"","Version":"7.7"}

有些情况下,我们的json字符串想全部以小写开头,则可以用如下方法指定输出时的字符串名称:

type Os struct {    Arch     string `json:"arch"`    Major    string `json:"major"`    Minor    string `json:"minor"`    Name     string `json:"name"`    Platform string `json:"platform"`    Version  string `json:"version"`}

可以直接用内置的接口进行序列化处理:

func main() {    linux := Os{        Arch: "x86_64",        Major: "7",        Minor: "7",        Name: "CentOS Linux",        Platform: "centos",        Version: "7.7",    }    js, err := json.Marshal(linux)    if err != nil {        return    }    fmt.Println(string(js))}

输出:

{"arch":"x86_64","major":"7","minor":"7","name":"CentOS Linux","platform":"centos","version":"7.7"}

如果某个字段没有赋值,例如Platform:

func main() {    linux := Os{        Arch: "x86_64",        Major: "7",        Minor: "7",        Name: "CentOS Linux",        Version: "7.7",    }    js, err := json.Marshal(linux)    if err != nil {        return    }    fmt.Println(string(js))}

输出:

{"arch":"x86_64","major":"7","minor":"7","name":"CentOS Linux","platform":"","version":"7.7"}

可以看到json字符串中仍然生成了platform这个字段,如果想对于某些不赋值的字段在生成json串的时候忽略掉,则可以在定义结构体的时候,使用omitempty,定义如下:

type Os struct {    Arch     string `json:"arch"`    Major    string `json:"major"`    Minor    string `json:"minor"`    Name     string `json:"name"`    Platform string `json:"platform,omitempty"`    Version  string `json:"version"`}func main() {    linux := Os{        Arch: "x86_64",        Major: "7",        Minor: "7",        Name: "CentOS Linux",        Version: "7.7",    }    js, err := json.Marshal(linux)    if err != nil {        return    }    fmt.Println(string(js))}

输出:

{"arch":"x86_64","major":"7","minor":"7","name":"CentOS Linux","version":"7.7"}

注意注意注意:

`json:"platform,omitempty"`

这个字符串中不能包含空格,否则无效
例如结构体中定义为:

Platform string `json: "platform,omitempty"`

这种json:后面跟空格,则不能指定json序列化时候显示的成员名称,默认是结构体成员名,即Platform

{"arch":"x86_64","major":"7","minor":"7","name":"CentOS Linux","Platform":"","version":"7.7"}

文章来源:智云一二三科技

文章标题:golang 结构体

文章地址:https://www.zhihuclub.com/5932.shtml

关于作者: 智云科技

热门文章

网站地图