Неожиданное возвращение анонимной структуры

Я пытаюсь реализовать метод, который возвращает модифицированную структуру, основанную на оригинальной, например:

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

Любая помощь будет оценена.

2 ответа

Решение

С "истинно" анонимной структурой возвращаемого значения

Если вы хотите использовать анонимное возвращаемое значение структуры, это будет выглядеть ужасно.

Зачем? Потому что, когда вы определяете тип возвращаемого значения, вы должны описать анонимную структуру. И когда вы пишете return оператор, вы должны предоставить возвращаемое значение, которое будет являться структурным литералом. Структурный литерал для анонимной структуры также должен описывать структуру!

Когда вы пытаетесь написать это:

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

Этот синтаксис не тот, что вы думаете: он не содержит определения структуры. В основном в вашем примере первый { это открывающая скобка анонимного определения структуры, а не открывающая скобка тела функции. И как таковой, последующий 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
}

И если вы также добавите оператор return, который должен повторять определение анонимной структуры:

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

&{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):

{1 bobie <nil> <nil>}

Замечания:

Встраивание не является обязательным, но в этом случае поля встроенного типа (BaseProject) будет продвигаться и поэтому вы можете ссылаться на них как p.Id как будто они были определены в Project, Определение его как обычного поля также будет работать.

Спецификация языка программирования 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() {}
Другие вопросы по тегам