#go #interface
#Вперед #интерфейс
Вопрос:
Новое для перехода сюда. Я наткнулся на некоторый код, который имеет следующее отношение к DynamoDB:
type Dynamo interface {
DescribeTableWithContext(
aws.Context,
*dynamodb.DescribeTableInput,
...request.Option,
) (*dynamodb.DescribeTableOutput, error)
}
type my_struct struct {
Dynamo
}
Правильно ли я предполагаю, что my_struct
«реализует» интерфейс Dynamo и теперь может использовать DescribeTableWithContext
метод?
Комментарии:
1. Больше похоже, что он только удовлетворяет интерфейсу, однако попытка вызвать метод в экземпляре my_struct без реальной, конкретной реализации завершится неудачей во время выполнения .
2. Это означает то же самое, что если бы внутри находился неинтерфейсный тип: это встраивание и работает как обычное встраивание, т. Е. у вас есть безымянное поле этого типа, и, как и в случае с типами указателей или карт, вы должны инициализировать его, прежде чем оно станет пригодным для использования.
Ответ №1:
Прав ли я, предполагая, что my_struct «реализует» интерфейс Dynamo
Не совсем. Какая бы структура, которую вы ни инициализировали my_struct
для Dynamo
внедрения, будет тем, что реализует интерфейс. my_struct
однако будет удовлетворять Dynamo
интерфейсу во время компиляции. Однако, как указывает @mkopriva, во время выполнения это требует конкретной реализации встроенного интерфейса. Итак, если бы вы должны были сделать что-то вроде этого:
package main
import "fmt"
type Adder interface {
func Add(a, b int) int
}
type Embed struct {
Adder
}
func PrintAdd(a Adder, first, second int) {
fmt.Println(a.Add(first, second))
}
func main() {
e := Embed{}
PrintAdd(e, 1, 2)
}
Этот код будет скомпилирован, но во время выполнения вызов PrintAdd
завершится неудачей, поскольку реализация встроенного интерфейса не была установлена.
Если вы замените вышеупомянутый main на:
type adder struct {}
func (a adder) Add(first, second int) int {
return first second
}
func main() {
e := Embed{adder{}}
PrintAdd(e, 1, 2)
}
Все будет работать так, как ожидалось.
… и теперь можете использовать метод DescribeTableWithContext?
Да, предполагая, что вы предоставили реализацию интерфейса во время инициализации.
РЕДАКТИРОВАТЬ: Добавлено объяснение того, что значит реализовать интерфейс, а не просто удовлетворять ему.
Комментарии:
1. Ваше начальное утверждение неверно. Встраивание типа интерфейса в определение структуры не означает, что структура реализует интерфейс. Для вызывающих будет казаться, что это так, но вызовы (в вашем примере)
Add
ona
действительно будут ретранслироваться в экземпляр,adder
назначенныйa.Adder
. Если быEmbed
нужно было реализоватьAdd
себя, то вместо этого был бы вызван этот метод (переопределяющий), учитывая, что вызывающий объект явно не обходит его вызовомa.Adder.Add
.2. Просто обновил свой ответ, чтобы быть более конкретным в отношении того, что значит удовлетворять, а не реализовывать интерфейс. Справедливое замечание, спасибо за ответ.
Ответ №2:
Прав ли я, предполагая, что my_struct»реализует» интерфейс Dynamo и теперь может использовать метод DescribeTableWithContext?
Нет. Что это делает, так это встраивает неназванное поле типа Dynamo
в вашу структуру. Вы сможете вызывать DescribeTableWithContext
непосредственно экземпляры my_struct
(например, var my_struct_instance my_struct
), но этот вызов фактически вызовет реализацию того, что вы назначили my_struct_instance.Dynamo
, а не реализацию внутри my_struct
(потому что это не определяет DescribeTableWithContext
и, следовательно, не реализует Dynamo
). Выполнение этого может пройти успешно (т. Е. без паники) только после установки my_struct_instance.Dynamo
значения (или указателя на значение) с типом, который реализует Dynamo
. Реализация интерфейсов в Go выполняется с помощью утиного ввода.