Реализовать «Stringer» абстрактно на основе интерфейса

Я пытаюсь реализовать интерфейс «абстрактно». Под этим я подразумеваю, что пытаюсь реализовать метод(ы) этого интерфейса с точки зрения методов другого интерфейса.

Вот что я пробовал (но это не работает, потому что нам не разрешено использовать тип интерфейса в качестве получателя):

package symbols

import "fmt"

type Symbol interface {
    Name() string
}

type TerminalSymbol struct {
    rune rune
}

func (t TerminalSymbol) Name() string {
    return `'` + string(t.rune) + `'`
}

type NonTerminalSymbol struct {
    name string
}

func (nt NonTerminalSymbol) Name() string {
    return nt.name
}

/////////////////////////////////////////////////////////
/// Try to implement 'Stringer' interface for Symbols

func (s Symbol) String() string {
    //^ ERROR: invalid receiver type Symbol (pointer or interface type)
    return fmt.Sprintf("A symbol with name: %v", s.Name())
}

Я полагаю, компилятор go, по сути, говорит мне, что реализация одного интерфейса на основе другого интерфейса просто не поддерживается?

Я полагаю, я мог бы просто понять намек и просто сделать это вместо этого:

func (s NonTerminalSymbol) String() string {
    return fmt.Sprintf("A symbol with name: %v", s.Name())
}

func (s TerminalSymbol) String() string {
    return fmt.Sprintf("A symbol with name: %v", s.Name())
}

Это работает, но в итоге дублирует реализацию метода 'String'.

В Java мы можем легко избежать такого дублирования; например путем добавления конкретных методов в абстрактный класс; или добавив реализацию «по умолчанию» к некоторым методам в интерфейсе.

Есть ли «идиоматический» способ сделать это на ходу? (то есть можем ли мы сделать абстрактный тип, такой как Symbol, реализовать Stringer, не дублируя реализацию String().

Создание API ввода вопросов на разных языках программирования (Python, PHP, Go и Node.js)
Создание API ввода вопросов на разных языках программирования (Python, PHP, Go и Node.js)
API ввода вопросов - это полезный инструмент для интеграции моделей машинного обучения, таких как ChatGPT, в приложения, требующие обработки...
2
0
54
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

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

В Go интерфейс — это просто список методов, и концепция наследования классов не существует. Вы можете создавать иерархии объектов, используя встраивание типов, но это не обеспечивает позднего связывания, необходимого для реализации этого.

Однако вы можете сделать это:

Создайте функцию стрингера для символов:

func SymbolToString(s Symbol) string {
       return fmt.Sprintf("A symbol with name: %v", s.Name())
}

Теперь вы можете написать простую реализацию метода String для каждой структуры:

type NonTerminalSymbol struct {
    name string
}

func (n NonTerminalSymbol) String() string {return SymbolToString(n)}

Спасибо, я думаю, вы подтвердили то, что я думал (я просто не был уверен, что это действительно невозможно, я просто подозревал это). Я нахожу это несколько удивительным и хотел бы понять логику этого. Но я полагаю, что это действительно другой вопрос. Поэтому я приму этот ответ и, возможно, подумаю о создании еще одного вопроса, который спрашивает «почему».

Kris 04.04.2022 03:40

Простой ответ заключается в том, что получатель метода не знает, встроен ли он в другую структуру. Внедрение типов — это единственный способ составления наборов методов, и у метода нет информации о времени выполнения, чтобы решить, во что он встроен.

Burak Serdar 04.04.2022 03:43

Вы можете делать «абстрактные» реализации, которые не требуют поздней привязки, хотя ваш пример не такой.

Burak Serdar 04.04.2022 03:45

Другие вопросы по теме

Как правильно реализовать этот дизайн?
Как я могу соединить два класса (которые не знают друг друга) через публичный интерфейс (С++)
Ошибка конфигурации: вы должны настроить хотя бы один набор аргументов для этого @ParameterizedTest
Структура Golang не соответствует требованиям интерфейса в возвращаемом типе метода
Как использовать члены типа (=статические) в общей настройке
Диспетчеризация/выбор метода контравариантных интерфейсов C#
Конфликт модификатора видимости в объявлении интерфейса в Kotlin
Хороший способ выполнения общих блоков кода в том же контексте обертки, поддерживающий java.lang.Exception без параметров ввода/вывода?
Интерфейс или тип с объектом в качестве ключа в машинописном тексте
Можно ли реализовать интерфейс для типа, который я не могу изменить (в контексте функции предварительного просмотра С#: члены статического абстрактного интерфейса)