Как использовать runtime.Object для создания общих функций CRD в go [duplicate]

Как отбрасывать из точечного объекта в объект подпункта?

Вы не можете; если только point не имеет оператора преобразования, или subpoint имеет конструктор преобразования, и в этом случае типы объектов могут быть преобразованы без необходимости приведения.

Вы можете использовать из point ссылка (или указатель) на ссылку subpoint (или указатель), если упомянутый объект действительно имеет тип subpoint:

subpoint s;

point & a = s;
subpoint & b1 = static_cast<subpoint&>(a);
subpoint & b2 = dynamic_cast<subpoint&>(a);

Первый (static_cast) более опасен; нет проверки, что преобразование действительно, поэтому, если a не ссылается на subpoint, то использование b1 будет иметь неопределенное поведение.

Второй (dynamic_cast) является безопаснее, но будет работать, только если point является полиморфным (то есть, если он имеет виртуальную функцию). Если a ссылается на объект несовместимого типа, тогда он выдает исключение.

38
задан Flimzy 12 April 2017 в 15:14
поделиться

5 ответов

Это очень похоже на вопрос, на который я только что ответил: https://stackoverflow.com/a/12990540/727643

Короткий ответ: вы правы. Кусочек структур не равен фрагменту интерфейса, реализуемого структурой.

A []Person и []Model имеют разные макеты памяти. Это связано с тем, что типы, на которых они расположены, имеют разные макеты памяти. A Model - значение интерфейса, что означает, что в памяти это два слова по размеру. Одно слово для информации о типе, другое для данных. A Person - это структура, размер которой зависит от полей, которые он содержит. Чтобы преобразовать из []Person в []Model, вам нужно будет перебрать массив и выполнить преобразование типа для каждого элемента.

Поскольку это преобразование является операцией O (n) и приведет к созданию нового среза, Go отказывается делать это неявно. Вы можете сделать это явно со следующим кодом.

models := make([]Model, len(persons))
for i, v := range persons {
    models[i] = Model(v)
}
return models

И, как указал dskinner , вы, скорее всего, хотите фрагмент указателей, а не указатель на фрагмент. Указатель на срез обычно не нужен.

*[]Person        // pointer to slice
[]*Person        // slice of pointers
66
ответ дан Community 15 August 2018 в 19:57
поделиться
  • 1
    В то время я не понимал, но мой ответ прямо не затрагивает поднятый вопрос. Этот ответ обращается к нему. – dskinner 21 October 2012 в 05:12
  • 2
    Очень хороший ответ, особенно с объяснением количества слов памяти для каждого типа – I82Much 21 October 2012 в 18:16
  • 3
  • 4
    Ну, как вы пишете что-то абстрактным, общим образом? Представьте, что у вас есть 100k результатов из запроса к базе данных, и вам нужно перебирать их все и создавать копии каждого набора данных. Это означает, что вы не можете иметь общие интерфейсы в Go – user 26 April 2017 в 14:58

Возможно, это проблема с вашим типом возвращаемого значения *[]Person, где на самом деле должно быть []*Person, чтобы ссылаться на то, что каждый индекс среза является ссылкой на Person, и где срез [] равен сама по себе ссылка на массив.

Обратите внимание на следующий пример:

package main

import (
    "fmt"
)

type Model interface {
    Name() string
}

type Person struct {}

func (p *Person) Name() string {
    return "Me"
}

func NewPersons() (models []*Person) {
    return models
}

func main() {
    var p Model
    p = new(Person)
    fmt.Println(p.Name())

    arr := NewPersons()
    arr = append(arr, new(Person))
    fmt.Println(arr[0].Name())
}
7
ответ дан dskinner 15 August 2018 в 19:57
поделиться
  • 1
    Спасибо за ответ. Хотя (как вы отметили), он не затрагивает проблему напрямую, но тем не менее это оцененный пример :-) – Jon L. 21 October 2012 в 05:27

Поскольку Стивен уже ответил на вопрос, и вы начинающий, я подчеркиваю, что даю советы.

. Лучше работать с интерфейсами go - это не иметь конструктора, возвращающего интерфейс, как вы могли бы использовать с другими языками, такими как java, но иметь конструктор для каждого объекта независимо, поскольку они реализуют интерфейс неявно.

Вместо

newModel(type string) Model { ... }

вы должны сделать

newPerson() *Person { ... }
newPolitician() *Politician { ... }

с Person и Politician, реализующими методы Model. Вы все равно можете использовать Person или Politician везде, где принят Model, но вы также можете реализовать другие интерфейсы.

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

Предположим, что у меня есть Person, который реализует метод Walk() и Model реализует ShowOff(), следующее не будет работать прямо:

newModel("person").ShowOff()
newModel("person").Walk() // Does not compile, Model has no method Walk

Однако это будет:

newPerson().ShowOff()
newPerson().Walk()
7
ответ дан nemo 15 August 2018 в 19:57
поделиться
  • 1
    Вы правы :-( Мой подход - это моя попытка предоставить доступ к моделям через API-интерфейс ReST. Таким образом, запрос к /api/{collection} будет динамически взаимодействовать с запрашиваемой коллекцией. Можете ли вы предложить альтернативное решение без явного тестирования запрошенного сбор через несколько функций? Я предполагаю, что я ищу способ указать общий тип возврата, не теряя знания своего типа. – Jon L. 21 October 2012 в 05:45
  • 2
    Знание этого типа всегда сохраняется, даже если вы вернетесь interface{}, проблема в том, что вам нужно выполнять утверждения типа времени выполнения вместо проверки типа компилятора. Общее решение для name -> object без утверждений времени исполнения возможно только с использованием дженериков, которые не поддерживаются. Поэтому, если вы это сделаете, вам нужно жить с отражением или недостатками вашего решения. – nemo 21 October 2012 в 15:13
  • 3
    point [] Model! = [] Лицо или даже [] Модель! = [] Политик. Это проблема. – user 26 April 2017 в 15:05
  • 4
    @dalu Правильно. Я также упоминаю это в верхней части моего ответа: этот ответ дает дополнительную информацию о типизации и выводе интерфейсов, о которых OP, похоже, не знал, но принятый ответ не рассматривался. – nemo 26 April 2017 в 17:07

Как уже ответили другие, [] T - особый тип. Я хотел бы добавить, что простая простая утилита может использоваться для их общего преобразования.

import "reflect"

// Convert a slice or array of a specific type to array of interface{}
func ToIntf(s interface{}) []interface{} {
    v := reflect.ValueOf(s)
    // There is no need to check, we want to panic if it's not slice or array
    intf := make([]interface{}, v.Len())
    for i := 0; i < v.Len(); i++ {
        intf[i] = v.Index(i).Interface()
    }
    return intf
}

Теперь вы можете использовать его следующим образом:

ToIntf([]int{1,2,3})
2
ответ дан slavikm 15 August 2018 в 19:57
поделиться

Типы T и [] T являются различными типами, и они отличаются друг от друга, даже если они удовлетворяют одному и тому же интерфейсу. IOW, каждый тип, удовлетворяющий модели, должен реализовать все методы модели самостоятельно - приемником метода может быть только один конкретный тип.

2
ответ дан zzzz 15 August 2018 в 19:57
поделиться
Другие вопросы по тегам:

Похожие вопросы: