Как контравариантные типы работают в golang 1.18 с дженериками?

В golang 1.18 я хотел бы определить следующую функцию:

func Pipe[A, T1, T2 any](left func(A) T1, right func(T1) T2) func(A) T2 {
    return func(a A) T2 {
        return right(left(a))
    }
}

например вывод функции left должен быть вводом функции right, представленным в виде дженериков.

Я замечаю, что это не работает должным образом для следующего примера:

func OpenFile(name string) *os.File {
...
}

func ReadAll(rdr io.Reader) []byte {
...
}

var OpenRead = Pipe(OpenFile, ReadAll)

Это не удается скомпилировать, потому что компилятор считает T1*os.File, и хотя он совместим с io.Reader, он не идентичен.

Если бы я вызывал цепочку без таких шаблонов:

var result = ReadAll(OpenFile("test"))

затем компилятор идентифицирует совместимые типы.

Вопросы:

  • Есть ли способ в дженериках golang 1.18 исправить подпись Pipe, чтобы обеспечить желаемое поведение?
  • поведение golang 1.18 задумано или это ошибка?

Спасибо за разъяснение. Надеюсь, со временем это изменится...

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

Ответы 1

Ответ принят как подходящий
  1. Нет.
  2. Нет, не ошибка. См. Часто задаваемые вопросы.

Учитывая, что Go не поддерживает ковариантные типы результатов, вам нужно преобразовать результат left в тип, принятый right. Однако в настоящее время нет способа выразить конвертируемость использует параметры типа.

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

func Pipe[A, T1, T2, T3 any](left func(A) T1, right func(T2) T3) func(A) T3 {
    return func(a A) T3 {
        return right((interface{})(left(a)).(T2))
    }
}

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