Unexpected return of anonymous struct

2020-07-17 06:40发布

I am trying to implement a method that returns a modified struct based on the original one, such as:

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

And I get the following error:

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

Any help would be appreciated.

标签: struct go
2条回答
beautiful°
2楼-- · 2020-07-17 07:11

The Go Programming Language Specification

Keywords

The following keywords are reserved and may not be used as identifiers.

break        default      func         interface    select
case         defer        go           map          struct
chan         else         goto         package      switch
const        fallthrough  if           range        type
continue     for          import       return       var

.

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

struct is a reserved keyword.

Without more information about what you are trying to do, it's hard to know what you want, pehaps something like this?

package main

import (
    "encoding/json"
)

type Scheme struct{}

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

type UserProject struct {
    Username string
    Project
}

func (u *UserProject) GetProject() *Project {
    return &u.Project
}

func main() {}
查看更多
小情绪 Triste *
3楼-- · 2020-07-17 07:15

With "truly" anonymous struct return value

If you want to use an anonymous struct return value, that's gonna look really ugly.

Why? Because when you define the return type, you have to describe the anonymous struct. And when you write a return statement, you have to provide the return value which will be a struct literal. A struct literal for an anonymous struct also has to describe the struct!

When you attempt to write this:

func (p *Project) OmitUsername() *struct {
    // return somethig
}

This syntax is not what you think: it doesn't contain the struct definition. Basically in your example the first { is the opening bracket of the anonymous struct definition, and not the opening bracket of the function body. And as such, the subsequent return is interpreted as being inside the anonymous struct definition which is invalid syntax, this is exactly what the error message states too ("syntax error: unexpected return").

It should look like this:

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

And if you also add the return statement which has to repeat the anonymous struct definition:

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

Yes, it's ugly. You can make it a little simpler by using named return value, and not returning a pointer, because zero value of pointers is nil, and to return something, you'd have to initialize it which would also involve repeating the anonymous struct! If you use a non-pointer, named return value, you will have a value of the anonymous struct right away, and you don't have to repeat the anonymous struct definition again, just assign values to its fields:

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
}

Using them:

p := Project{"Bob", 1, "bobie", nil, nil}
fmt.Println(p.OmitUsername())
fmt.Println(p.OmitUsername2())

Output (try these on the Go Playground):

&{1 bobie <nil> <nil>}
{1 bobie <nil> <nil>}

Still ugly...

With another named type, using embedding

...Best would be to provide another named type to return and not an anonymous struct. You may utilize embedding to make this solution practical and short:

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
}

Using it:

p := Project{BaseProject{1, "bobie", nil, nil}, "Bob"}
fmt.Println(p.OmitUsername())

Output (try this on the Go Playground):

{1 bobie <nil> <nil>}

Note:

Embedding is not really necessary, but this way the fields of the embedded type (BaseProject) will be promoted and so you can refer to them like p.Id as if they were defined in Project. Defining it as a regular field would also work.

查看更多
登录 后发表回答