Неожиданное возвращение анонимной структуры
Я пытаюсь реализовать метод, который возвращает модифицированную структуру, основанную на оригинальной, например:
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() {}