Как сделать функцию, которая получает массив пользовательских интерфейсов - PullRequest
0 голосов
/ 26 января 2019

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

У меня есть такая структура:

type Animal interface {
    speak() string
}

type Cat struct {
    Name string
}

type Dog struct {
    Race string
}

И я хочу, чтобы структуры реализовали интерфейс, япоступим так:

   func (c Cat) speak() string {
    return "Miaw!"
}

func (d Dog) speak() string {
    return "Guau!"
}

func speak(a Animal) string {
    return a.speak()
}

func speaks(a []Animal) string {
    str := ""
    for i := 0; i < len(a); i++ {
        str += a[i].speak()
    }
    return str
}

Итак, что я создал: метод speak получает Animal и выполняет метод, говоря о заданной структуре (Animal, что Cat илиDog), а метод speaks получает срез Animal и выполняет метод, говорящий о структуре, указанной в каждом индексе среза (Animal, который равен Cat или Dog).

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

func test()  {
    cat1 := Cat{
        Name: "Cat1",
    }

    cat2 := Cat{
        Name: "Cat2",
    }

    cat3 := Cat{
        Name: "Cat3",
    }

    arrayCats := []Cat{cat1, cat2, cat3}
    speak(cat1)
    speak(cat3)
    speak(cat2)
    speaks(arrayCats) //This line gives an error to the Compiler
}

Я загружаю ошибку, которую дает мне компилятор:

Error_compiler

Может кто-нибудь объяснить мне, почему я могу играть с polimorfish в функциях, которые получают только один элемент, и почему нет в функции, которая получает фрагмент этого элемента?

Мне действительно нужно найтирешение этого профиРеализовать его в различных частях моего приложения, и я понятия не имею, как решить проблему, ни как реализовать практичное и масштабируемое решение (фрагмент в реальном приложении будет содержать большое количество элементов).

Мне показались полезными эти ответы, чтобы лучше понять мою проблему, но я все еще не понимаю, в чем заключается проблема или решение: Ответ1 Ответ2 Ответ3

Ответы [ 2 ]

0 голосов
/ 26 января 2019

Фиксированная версия, на Play

Как уже упоминалось, в Go нет автоматического приведения типов. И [] Кошка совершенно отличается от [] Животного.

Все, что вам действительно нужно было сделать, это создать фрагмент типа, который вы передадите методу speaks.
Итак, измените:

arrayCats := []Cat{cat1, cat2, cat3}

до

arrayCats := []Animal{cat1, cat2, cat3}

И это прекрасно работает.

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

Такие вещи, как int, не являются объектами в Java, поэтому вы не можете создать List<int>, потому что тогда трюк List<Object> не сработает. Потому что int не является подклассом Object.

В go нет общего базового типа для таких вещей, как struct, поэтому нет реального способа выполнить трюк приведения, который делает java.

Как уже упоминали другие, есть также некоторые специфические особенности того, как go управляет памятью, благодаря чему такие вещи, как автоконвертация, не работают в общем виде (то есть: фрагмент int64 - это другой объем памяти, чем фрагмент int32, поэтому не может быть вычтен без выделения).

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

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

0 голосов
/ 26 января 2019

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

Причина: go не скрывает от вас выделения памяти, поэтому вам нужно создавать новое и чувствовать его вручную.

https://golang.org/doc/faq#convert_slice_of_interface

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...