Идиоматический способ написать метод, который работает с универсальным типом

Как идиоматично написать метод, работающий с «универсальным» массивом?

У меня есть типизированный массив:

a := make([]int, 0)

Я хочу написать простой метод, который мог бы работать с массивом любого типа:

func reverse(a []interface{}) []interface{} {
    for i, j := 0, len(a)-1; i < j; i, j = i+1, j-1 {
        a[i], a[j] = a[j], a[i]
    }
    return a
}

Использование этого метода a = reverse(a) дает мне 2 ошибки:

cannot use a (type []int) as type []interface {} in argument to reverse
cannot use reverse(a) (type []interface {}) as type []int in assignment
golang.org/doc/faq#convert_slice_of_interface. Или короче: вы не можете. Вы должны прибегнуть к рефлексии.
Volker 20.06.2019 05:48

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

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

Ответы 3

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

Пока не появятся дженерики (которые, скорее всего, будут называться контракты), отражение и интерфейсы — единственные инструменты для достижения такого обобщения.

Вы можете определить reverse() так, чтобы оно принимало значение interface{}, и использовать пакет reflect для его индексации и замены элементов. Обычно это медленно, и его сложнее читать/обслуживать.

Интерфейсы обеспечивают более приятный способ, но требуют, чтобы вы писали методы для разных типов. Взгляните на пакет sort, особенно на функцию sort.Sort():

func Sort(data Interface)

Где sort.Interface:

type Interface interface {
        // Len is the number of elements in the collection.
        Len() int
        // Less reports whether the element with
        // index i should sort before the element with index j.
        Less(i, j int) bool
        // Swap swaps the elements with indexes i and j.
        Swap(i, j int)
}

sort.Sort() может сортировать любые слайсы, которые реализуют sort.Interface, любые слайсы, которые имеют методы, необходимые алгоритму сортировки для выполнения своей работы. Преимущество этого подхода в том, что вы можете сортировать и другие структуры данных, а не только срезы (например, связанный список или массив), но обычно используются срезы.

Терпение! Согласно последний проект предложения по добавлению параметров типа к языку, вы сможете написать такую ​​общую функцию reverse в будущей версии Go:

func reverse[T any](s []T) []T {
    for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
        s[i], s[j] = s[j], s[i]
    }
    return s
}

func main() {
    s := []int{1, 2, 3, 4, 5}
    s = reverse(s)
    fmt.Println(s)
}

(игровая площадка)

Не то чтобы вы могли использовать дженерики в производстве на данный момент (по состоянию на 2 октября 2020 г.), но для людей, заинтересованных в предстоящей функции дженериков go, с последней версией эскизный проект go вы можете написать универсальную функцию reverse, как показано ниже.

package main

import (
    "fmt"
)

func reverse[T any](s []T) []T {
    for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
        s[i], s[j] = s[j], s[i]
    }
    return s
}

func main() {
    s := []int{1, 2, 3, 4, 5}
    s = reverse(s)
    fmt.Println(s)
}

Выход:

[5 4 3 2 1]

Не сильно отличается от моего предыдущего ответа, не так ли?

jub0bs 16.10.2020 13:10

@ jub0bs В вашем коде до последнего редактирования использовался синтаксис из прошлогоднего черновика.

Mayank Patel 16.10.2020 14:52

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