Да, в общем случае вам нужно утверждение типа (или переключатель типа ), чтобы вернуть перенесенное значение в значение интерфейса.
Но выне нужно возвращать сохраненное конкретное значение из интерфейса, чтобы иметь возможность вызывать другие методы, которые у него есть (и которые не являются частью типа интерфейса).
Вы можете ввести другое значение интерфейса иззначение интерфейса, другое значение интерфейса, тип которого содержит методы, которые вы хотите вызвать.
См. этот пример:
type Foo interface {
Bar() string
}
type fooImpl struct{}
func (fooImpl) Bar() string { return "Bar from fooImpl" }
func (fooImpl) Baz() string { return "Baz from fooImpl" }
func main() {
var f Foo = &fooImpl{}
if x, ok := f.(interface{ Baz() string }); ok {
fmt.Println(x.Baz())
} else {
fmt.Println("f does not have a Baz() method!")
}
}
Foo
имеет только метод Bar()
.У нас есть переменная f
типа Foo
, конкретный тип, который она хранит, - *fooImpl
, у которой также есть другой метод: fooImpl.Baz()
.
Таким образом, мы можем ввести значение типа interface{ Baz() string }
и просто позвоните Baz()
, чтобы получить результат.
Вывод вышеизложенного (попробуйте на Go Playground ):
Baz from fooImpl
Утверждение типа интерфейса из другого значения интерфейса не требует экспорта типа переносимого значения.
Вы также можете создать новый тип для типа интерфейса, который вы вводите, анонимный тип не требуется:
type MyFoo interface{ Baz() string }
if x, ok := f.(MyFoo); ok {
fmt.Println(x.Baz())
} else {
fmt.Println("f does not have a Baz() method!")
}
Вывод такой же (попробуйте на Go Playground ).
Черт, вы даже можете "расширить" Foo
с помощью дополнительных методов,и введите asset «расширенный» интерфейс:
type MyFoo interface {
Foo
Baz() string
}
if x, ok := f.(MyFoo); ok {
fmt.Println(x.Bar())
fmt.Println(x.Baz())
} else {
fmt.Println("f does not have a Baz() method!")
}
Теперь в этом примере x
является одновременно Foo
и значением, которое имеет метод Baz()
.Вывод (попробуйте на Go Playground ):
Bar from fooImpl
Baz from fooImpl