意外返回匿名结构体

huangapple go评论78阅读模式
英文:

Unexpected return of anonymous struct

问题

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

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

我得到以下错误:

models/project.go:22: 语法错误:意外的 return
models/project.go:24: 非声明语句在函数体外
models/project.go:25: 非声明语句在函数体外
models/project.go:25: 语法错误:意外的字符串字面量,期望分号或换行符
models/project.go:26: 非声明语句在函数体外

希望能对你有所帮助。

英文:

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.

答案1

得分: 7

使用“真正”匿名结构体返回值

如果你想使用匿名结构体作为返回值,那么代码看起来会非常丑陋。

为什么呢?因为当你定义返回类型时,你必须描述匿名结构体。而当你编写一个return语句时,你必须提供将作为结构体字面值的返回值。对于匿名结构体的结构体字面值也必须描述结构体!

当你尝试编写以下代码时:

func (p *Project) OmitUsername() *struct {
    // 返回一些东西
}

这个语法不是你想的那样:它并不包含结构体定义。在你的例子中,第一个{是匿名结构体定义的左大括号,而不是函数体的左大括号。因此,后续的return被解释为在匿名结构体定义内部,这是无效的语法,这正是错误消息所指出的("syntax error: unexpected return")。

应该像这样编写:

func (p *Project) OmitUsername() *struct {
    Id     uint
    Alias  string
    Data   *json.RawMessage
    Scheme Scheme
} {
    // 然后在这里写返回语句
}

如果你还要添加返回语句,它必须重复匿名结构体的定义:

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

是的,这很丑陋。你可以通过使用具名返回值并且不返回指针来简化它,因为指针的零值是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
}

使用它们:

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

输出结果(在Go Playground上尝试):

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

仍然很丑陋...

使用另一个具名类型,使用嵌入

...最好的方法是提供另一个具名类型作为返回值,而不是匿名结构体。你可以利用_嵌入_来使这个解决方案实用和简洁:

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
}

使用它:

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

输出结果(在Go Playground上尝试):

{1 bobie <nil> <nil>}

注意:

嵌入并不是必需的,但这样做可以提升嵌入类型(BaseProject)的字段,因此你可以像p.Id一样引用它们,就像它们在Project中定义一样。将其定义为常规字段也可以工作。

英文:

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 (&quot;syntax error: unexpected return&quot;).

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 &amp;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{&quot;Bob&quot;, 1, &quot;bobie&quot;, nil, nil}
fmt.Println(p.OmitUsername())
fmt.Println(p.OmitUsername2())

Output (try these on the Go Playground):

&amp;{1 bobie &lt;nil&gt; &lt;nil&gt;}
{1 bobie &lt;nil&gt; &lt;nil&gt;}

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, &quot;bobie&quot;, nil, nil}, &quot;Bob&quot;}
fmt.Println(p.OmitUsername())

Output (try this on the Go Playground):

{1 bobie &lt;nil&gt; &lt;nil&gt;}

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.

答案2

得分: 3

《Go编程语言规范》

关键字

以下关键字是保留的,不能用作标识符。

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 是一个保留关键字。

根据您提供的信息不够详细,很难知道您想要什么,也许您想要类似以下的代码?

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() {}
英文:

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 (
	&quot;encoding/json&quot;
)

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 &amp;u.Project
}

func main() {}

huangapple
  • 本文由 发表于 2015年11月21日 00:25:40
  • 转载请务必保留本文链接:https://go.coder-hub.com/33831454.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定