Как вернуть пустой интерфейс в часть моего настраиваемого типа?

У меня есть 15 настраиваемых типов в этом приложении, и обработка, которую я хочу сделать с ними, на самом деле очень универсальна для них всех.

В каждом случае мне нужно перебирать срез любого типа, с которым я работаю.

интерфейс - это то, что в настоящее время передается, но, конечно, не должно оставаться таким

У меня такой код:

func ProcessSlice(in interface{}){
    switch reflect.TypeOf(p.in).Kind() {
    case reflect.Slice:
        s := reflect.ValueOf(p.in)

        for i := 0; i < s.Len(); i++ {
            fmt.Println(reflect.ValueOf(p.in))
        }
    }
}

fmt.Println предназначен для отладки, и я получаю следующий вид вывода:

[map[_Id:4K7qx_mUSbV-----------== name:<name ommited> _class:basic_organization] map[_Id:4K7qx_mUnvB-----------== name:<name omitted> _class:basic_organization]]

Мой настоящий вопрос здесь, скажем, у меня есть типы:

MyCustomStructA,
MyCustomeStructB

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

В вашем цикле вы снова делаете reflect.ValueOf(p.in). Вы имеете в виду s.Index(i)?

Gavin 13.09.2018 21:37

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

MickeyThreeSheds 13.09.2018 21:43
s.Index(i) даст вам Value элемента по этому индексу среза. Из этого вы сможете получить новый экземпляр с чем-то вроде reflect.New(s.Index(i).Type()).
Gavin 13.09.2018 21:47

Вы проверяли этот stackoverflow.com/questions/28954646/… ..? я думаю, что это очень похоже. .

Fendi jatmiko 13.09.2018 22:00
0
4
125
1

Ответы 1

Я бы предложил реализовать все эти настраиваемые типы с интерфейсом, который говорит, что они «обрабатываемые». Затем в ProcessSlice() вы можете перебирать элементы среза и обрабатывать те, которые реализуют интерфейс Processable. Что-то вроде этого:

// Processable is a type that can be 'processed'
type Processable interface {
    Process()
}

// ProcessSlice processes a slice of types that can be processed
func ProcessSlice(in interface{}) {
    switch reflect.TypeOf(in).Kind() {
    case reflect.Slice:
        s := reflect.ValueOf(in)

        for i := 0; i < s.Len(); i++ {
            v := s.Index(i).Interface()

            if p, ok := v.(Processable); ok {
                p.Process()
            }
        }
    }
}

Таким образом, вся логика обработки для типа может быть прикреплена к самому типу, и вам также не нужно будет изменять ProcessSlice() при добавлении новых пользовательских типов.

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

// ProcessSliceConcreteTypes processes a slice of types based on the type of the slice
func ProcessSliceConcreteTypes(in interface{}) {
    switch reflect.TypeOf(in).Kind() {
    case reflect.Slice:
        s := reflect.ValueOf(in)

        switch sv := s.Interface().(type) {
        case []S1:
            for _, s1 := range sv {
                s1.Process()
            }
        case []S2:
            for _, s2 := range sv {
                s2.Process()
            }
        default:
            // error here
        }
    }
}

(См. На Перейти на игровую площадку)

Мне тоже больше всего нравится ваша идея интерфейса! Но по какой-то причине я получаю ноль внутри цикла в примере кода.

MickeyThreeSheds 13.09.2018 23:50

@MickeyThreeSheds, где именно взять nil? Можете ли вы сделать ссылку на игровую площадку с помощью примера кода?

svsd 14.09.2018 04:40

Зачем вообще использовать пустой интерфейс и отражение на этом этапе? Ваша подпись может быть func ProcessSliceConcreteTypes(in []Processable), а затем вы просто перебираете срез, вызывая Process для каждого элемента.

Gavin 20.09.2018 19:05

@Gavin, который не будет работать, поскольку часть типов структур не эквивалентна части интерфейсов, поэтому код не будет компилироваться. (OP говорит I need to iterate over a slice of whatever type it is that I am working with.)

svsd 20.09.2018 19:10

Я думаю, что есть еще простой способ сделать это, используя компилятор для проверки типов и избегая отражения. Предполагая, что у каждого типа есть своя собственная логика обработки, почему бы не заставить срез этого типа реализовать интерфейс Processable? В этот момент эта функция по существу становится бесполезной, и slice.Process() может быть вызван из любого места, где slice - это фрагмент «любого типа, с которым я работаю» и реализует Processable.

Gavin 20.09.2018 19:18

@Gavin Да, это сработает, но я думаю, что это дублирование кода - это то, чего OP хочет избежать в первую очередь. Определение нового типа среза для каждой структуры с последующей реализацией slice.Process() означало бы почти дублирование ~ 10 строк кода (определение типа, реализация интерфейса для типа, цикл по элементам; вызов Process () для каждого) для каждого такого типа.

svsd 20.09.2018 19:35

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