Любое разумное решение для отсутствия ковариации массива / среза в Go? - PullRequest
6 голосов
/ 01 октября 2010

Проблема, с которой я только что столкнулся, заключается в том, что делать в следующем случае:

func printItems(header string, items []interface{}, fmtString string) {
  // ...
}

func main() {
  var iarr = []int{1, 2, 3}
  var farr = []float{1.0, 2.0, 3.0}
  printItems("Integer array:", iarr, "")
  printItems("Float array:", farr, "")
}

Go не имеет обобщений и не позволяет использовать ковариацию коллекции:

prog.go:26: cannot use iarr (type []int) as type []interface { } in function argument      
prog.go:27: cannot use farr (type []float) as type []interface { } in function argument

Идеи

Ответы [ 5 ]

7 голосов
/ 20 марта 2011

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

package main

import "fmt"

type List interface {
    At(i int) interface{}
    Len() int
}

func printItems(header string, items List) {
    for i := 0; i < items.Len(); i++ {
        fmt.Print(items.At(i), " ")
    }
    fmt.Println()
}

type IntList []int
type FloatList []float64

func (il IntList)   At(i int) interface{} { return il[i] }
func (fl FloatList) At(i int) interface{} { return fl[i] }

func (il IntList)   Len() int { return len(il) }
func (fl FloatList) Len() int { return len(fl) }

func main() {
    var iarr = []int{1, 2, 3}
    var farr = []float64{1.0, 2.0, 3.0}
    printItems("Integer array:", IntList(iarr))
    printItems("Float array:", FloatList(farr))
}

Определяя размер и индексирование списка для каждого типа, вы можете обращаться к ним «в общем». Конечно, дженерики все равно будут хороши, так что вам не нужно этого делать.

7 голосов
/ 02 октября 2010

На самом деле нет способа сделать это прямо сейчас без

  1. Превращение ваших []int и []float в []interface{}.
  2. Заставить printItems принять interface{} вместо []interface{}, а затем использовать отражение, аналогично тому, что делает пакет fmt.

Ни одно из этих решений не изящно.

5 голосов
/ 02 октября 2010

Пример использования отражения:

package main

import (
    "fmt"
    "reflect"
    "strings"
    "container/vector"
)

func printItems(header string, items interface{}, fmtString string) {
    value, ok := reflect.NewValue(items).(reflect.ArrayOrSliceValue)
    if !ok {
        panic("Not an array or slice")
    }

    stringBuilder := new(vector.StringVector)
    stringBuilder.Push(header)

    n := value.Len()
    for i := 0; i < n; i++ {
        stringBuilder.Push(fmt.Sprintf(fmtString, value.Elem(i).Interface()))
    }

    fmt.Println(strings.Join(*stringBuilder, ""))
}

func main() {
    var iarr = []int{1, 2, 3}
    var farr = []float{1.0, 2.0, 3.0}

    printItems("Integer array:", iarr, " %d,")
    printItems("Float array:", farr, " %.1f,")
}
2 голосов
/ 03 сентября 2014
package main

import "fmt"

func printItems(header string, items interface{}, fmtString string) {
  if intItems, ok := items.([]int); ok {
    fmt.Println(header, intItems)
  } else if floatItems, ok := items.([]float64); ok {
    fmt.Println(header, floatItems)
  }
}

func main() {
  var iarr = []int{1, 2, 3}
  var farr = []float64{1.0, 2.0, 3.0}
  printItems("Integer array:", iarr, "")
  printItems("Float array:", farr, "")
}

ИМХО, более элегантно, чем решение с использованием отражения.

0 голосов
/ 01 октября 2010
package main

func printItems(header string, items interface{}, fmtString string) {
  // ...
}

func main() {
  var iarr = []int{1, 2, 3}
  var farr = []float{1.0, 2.0, 3.0}
  printItems("Integer array:", iarr, "")
  printItems("Float array:", farr, "")
}

Посмотрите на похожие функции, такие как fmt.Printf (), в основном пакете Go документация и исходный код .

...