Итерация по интерфейсу

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

Вот моя первая неудачная попытка. В настоящее время, когда я запускаю его в своем реальном варианте использования, он всегда говорит «о, о!».

func DoTheThingToAllTheThings(data_interface interface{}) int { var numThings int switch data := data_interface.(type) { case map[interface{}]interface{}: numThings = len(data) for index, item := range data { DoTheThing(index, item) } case []interface{}: numThings = len(data) for index, item := range data { DoTheThing(index, item) } default: fmt.Println("uh oh!") } return numThings } 

Массив или карта могут содержать много разных вещей, поэтому не нужно пытаться сопоставлять все возможные входные данные.

В противном случае, есть ли способ перебрать массив или карту в Go, не зная точно, что это такое?

Функция fmt.Printf("%v\n", data_interface) делает именно то, что вы хотите. Он распечатает всю карту или массив, переданные ей.

Вы можете найти реализацию здесь: http://golang.org/src/pkg/fmt/print.go?h=printArg#L708

Линия ближе к концу printArg является ключевым:

 return p.printReflectValue(reflect.ValueOf(arg), verb, plus, goSyntax, depth 

Он использует пакет «reflect»: http://golang.org/pkg/reflect/ для запроса типа аргумента. Внутри p.printReflectValue здесь: http://golang.org/src/pkg/fmt/print.go?h=printArg#L862 Вы увидите два случая, в которых рассматриваются карты и структуры. Затем он использует рекурсию через printValue для управления содержимым.

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

 package main import ( "fmt" "reflect" ) type Player string type Board struct { Tboard [9]string Player1 Player Player2 Player } // ignore this function contents, I grabbed it from elsewhere. func makeBoard() *Board { b := &Board{Tboard: [9]string{}} for x := 0; x < len(b.Tboard); x++ { b.Tboard[x] = "X" fmt.Println(b.Tboard[x]) } b.Player1 = "George" b.Player2 = "Tim" fmt.Printf("Len: %v\n", len(b.Tboard)) // => 9 fmt.Printf("Contents: %v\n", b) fmt.Printf("Syntax: %#v\n", b) fmt.Printf("Type: %T\n", b) fmt.Println("Board:", b.Tboard) return b } func main() { myBoard := makeBoard() v := reflect.ValueOf(*myBoard) // v is of type Value t := v.Type() fmt.Printf("Value: %v %T\n", v, v) fmt.Printf("Type: %v %T\n", t, t) // would be a switch if t == reflect.TypeOf(*myBoard) { var b2 Board b2 = v.Interface().(Board) // cast the type interface{} into type Board fmt.Printf("v converted back to: %#v\n", b2) } else { fmt.Printf("t is not recognized") } } 

Обратите внимание, что тип v является main.Board , полное имя пакета, а не Board . Любая структура, для которой вы хотите это сделать, должна иметь экспортированный тип для отражения.

Чтобы ваш пример работал, вам нужно будет создать массив interface{} (или карту), чтобы определить правильный тип:

 // This won't work, as the .(type) would be []S someS := []S{S{}} DoTheThingToAllTheThings(someS) // This will: it will go in case []interface{}: someSI := make([]interface{}, len(someS)) for i, s := range someS { someSI[i] = s } DoTheThingToAllTheThings(someSI) 

См. Полный пример здесь .

Но это означает, что вы все равно будете работать с interface{} в своей функции DoTheThing .
Здесь нет никакого общего родового, как я упоминал в « Что было бы дженериками в Go? ».

  • Сколько стоит слишком много с ключевым словом C ++ 11 auto?
  • Как преобразовать первичный ключ из целого в последовательный?
  • Полезно ли использовать целочисленный столбец для хранения почтовых индексов США в базе данных?
  • Что такое лямбды типа Scala и каковы их преимущества?
  • Использование `inline` в F #
  • Получение типа System.Type из частичного имени типа
  • Что круто о дженериках, зачем их использовать?
  • .NET. Определите тип этого «classа» в статическом методе
  • PostgreSQL: разница между текстом и varchar (характер меняется)
  • Каков размер столбца int (11) в mysql в байтах?
  • Как разрешить «должен быть экземпляр строки, строка, заданная» до PHP 7?
  • Interesting Posts

    Где я должен установить двоичные файлы, которые не являются .deb?

    Процедуры связанных типов передачи в качестве аргументов

    Полноскоростное соединение 802.11n между двумя ноутбуками без точки доступа

    Почему не удаляет указатель на NULL?

    WOW (Windows в Windows) Запуск 32-разрядных приложений в Windows 7

    Как влияет динамическая переменная на производительность?

    ПК внезапно не включается. Вентилятор очень шумный и быстрый. Экран не включается слишком

    Windows: переместите программы (с записями реестра) на другой жесткий диск

    Применение ColorFilter к ImageView с помощью ShapedDrawable

    Где HttpContent.ReadAsAsync?

    Можно ли включить один файл CSS в другой?

    VirtualBox: использование физического раздела в качестве виртуального диска

    Как игнорировать проверку сертификата, когда ssl

    Django – проблема импорта типовых моделей

    Как я могу получить функциональность, похожую на Spy ++, в моем приложении C #?

    Давайте будем гением компьютера.