Type assertion b.(YZ) успешен, поскольку *Bar реализует Y и Z. Но z.X() не компилируется: в статическом интерфейсе YZ метода X нет.
Преобразование одного интерфейса в другой
Type assertion b.(YZ) успешен, поскольку *Bar реализует Y и Z. Но z.X() не компилируется: в статическом интерфейсе YZ метода X нет.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
Условие
В примере есть тип Bar, у которого реализованы методы X(), Y() и Z(). На их основе объявлены два интерфейса: XY, требующий методов X() и Y(), и YZ, требующий методов Y() и Z(). Вопрос: можно ли выполнить приведение переменной типа XY к типу YZ?
type Bar struct{}
func (b *Bar) X() {}
func (b *Bar) Y() {}
func (b *Bar) Z() {}
type XY interface {
X()
Y()
}
type YZ interface {
Y()
Z()
}
func main() {
var b XY = &Bar{}
z := b.(YZ) // Сработает ли это приведение?
z.X() // А этот вызов?
_ = z
}
Опишите, как работает приведение интерфейсов в Go, какие условия должны быть выполнены, и что произойдёт при попытке вызвать метод, отсутствующий в целевом интерфейсе.
Ответ
Type assertion b.(YZ) успешен, поскольку *Bar реализует Y и Z. Но z.X() не компилируется: в статическом интерфейсе YZ метода X нет.
Go проверяет assertion по динамическому типу значения, а доступные методы выражения — по его статическому типу. Поэтому после удаления z.X() можно вызывать z.Y() и z.Z().
Для безопасной проверки неизвестного значения используйте z, ok := b.(YZ): при несовпадении ok будет false вместо panic. Если нужен X, вызывайте его через b или явно проверяйте более широкий интерфейс. Прямое преобразование типа и runtime assertion — разные операции; синтаксис здесь именно assertion.