doujujian0052 2015-11-20 16:25
浏览 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.

  • 写回答

2条回答 默认 最新

  • dongwuchu0314 2015-11-20 16:45
    关注

    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.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 请问有人会紧聚焦相关的matlab知识嘛?
  • ¥50 yalmip+Gurobi
  • ¥20 win10修改放大文本以及缩放与布局后蓝屏无法正常进入桌面
  • ¥15 itunes恢复数据最后一步发生错误
  • ¥15 关于#windows#的问题:2024年5月15日的win11更新后资源管理器没有地址栏了顶部的地址栏和文件搜索都消失了
  • ¥100 H5网页如何调用微信扫一扫功能?
  • ¥15 讲解电路图,付费求解
  • ¥15 有偿请教计算电磁学的问题涉及到空间中时域UTD和FDTD算法结合的
  • ¥15 three.js添加后处理以后模型锯齿化严重
  • ¥15 vite打包后,页面出现h.createElement is not a function,但本地运行正常