意外返回匿名结构

Pie*_*Pah 4 struct go

我正在尝试实现一种基于原始结构返回修改后的结构的方法,例如:

type Project struct {
    Username string           
    Id       uint      
    Alias    string           
    Data     *json.RawMessage 
    Scheme   Scheme          
}

func (p *Project) OmitUsername() *struct {

    return &struct {
        Id      uint         
        Alias   string   
        Data    *json.RawMessage
        Scheme  Scheme          
    }{
        p.Id,
        p.Alias,
        p.Data,
        p.Scheme
    })
}
Run Code Online (Sandbox Code Playgroud)

我得到以下错误:

models/project.go:22: syntax error: unexpected return 
models/project.go:24: non-declaration statement outside function body 
models/project.go:25: non-declaration statement outside function body 
models/project.go:25: syntax error: unexpected string literal, expecting semicolon or newline 
models/project.go:26: non-declaration statement outside function body
Run Code Online (Sandbox Code Playgroud)

任何帮助,将不胜感激。

icz*_*cza 5

具有“真正”匿名结构的返回值

如果要使用匿名struct返回值,那看起来真的很丑。

为什么?因为在定义返回类型时,必须描述匿名结构。而且,当您编写return语句时,必须提供返回值,该返回值将是结构文字。匿名结构的结构文字也必须描述该结构!

当您尝试编写此代码时:

func (p *Project) OmitUsername() *struct {
    // return somethig
}
Run Code Online (Sandbox Code Playgroud)

这种语法与您的想法无关:它不包含struct定义。基本上在您的示例中,第一个{是匿名struct定义的左括号,而不是函数主体的左括号。因此,后续return语句被解释为位于无效语法的匿名结构定义中,这也正是错误消息指出的内容("syntax error: unexpected return")。

它看起来应该像这样:

func (p *Project) OmitUsername() *struct {
    Id     uint
    Alias  string
    Data   *json.RawMessage
    Scheme Scheme
} {
    // And now here comes the return statement
}
Run Code Online (Sandbox Code Playgroud)

如果还添加了return语句,该语句必须重复匿名struct定义:

func (p *Project) OmitUsername() *struct {
    Id     uint
    Alias  string
    Data   *json.RawMessage
    Scheme Scheme
} {
    return &struct {
        Id     uint
        Alias  string
        Data   *json.RawMessage
        Scheme Scheme
    }{p.Id, p.Alias, p.Data, p.Scheme}
}
Run Code Online (Sandbox Code Playgroud)

是的,这很丑。您可以通过使用命名的返回值而不返回指针来简化操作,因为指针的零值为nil,并且要返回某些内容,则必须对其进行初始化,这也将涉及重复匿名结构!如果使用名为返回值的非指针,则将立即拥有匿名结构的值,并且不必再次重复匿名结构定义,只需将值分配给其字段即可:

func (p *Project) OmitUsername2() (ret struct {
    Id     uint
    Alias  string
    Data   *json.RawMessage
    Scheme Scheme
}) {
    ret.Id = p.Id
    ret.Alias = p.Alias
    ret.Data = p.Data
    ret.Scheme = p.Scheme
    return
}
Run Code Online (Sandbox Code Playgroud)

使用它们:

p := Project{"Bob", 1, "bobie", nil, nil}
fmt.Println(p.OmitUsername())
fmt.Println(p.OmitUsername2())
Run Code Online (Sandbox Code Playgroud)

输出(在Go Playground上尝试这些):

&{1 bobie <nil> <nil>}
{1 bobie <nil> <nil>}
Run Code Online (Sandbox Code Playgroud)

还是很丑

对于另一个命名类型,使用嵌入

...最好是提供另一个要返回的命名类型,而不是匿名结构。您可以利用嵌入使该解决方案实用且简短:

type BaseProject struct {
    Id     uint
    Alias  string
    Data   *json.RawMessage
    Scheme Scheme
}

type Project struct {
    BaseProject
    Username string
}

func (p *Project) OmitUsername() BaseProject {
    return p.BaseProject
}
Run Code Online (Sandbox Code Playgroud)

使用它:

p := Project{BaseProject{1, "bobie", nil, nil}, "Bob"}
fmt.Println(p.OmitUsername())
Run Code Online (Sandbox Code Playgroud)

输出(在Go Playground上尝试):

{1 bobie <nil> <nil>}
Run Code Online (Sandbox Code Playgroud)

注意:

嵌入并不是真正必要的方法,但是通过这种方式,BaseProject可以提升嵌入类型()的字段,因此您可以像p.Id在中定义它们一样对其进行引用Project。将其定义为常规字段也可以。