Утвердить интерфейс к своему типу
Я не могу изящно получить пиксели изображения в виде массива в общем случае.
f, err := os.Open(imgPath)
check(err)
defer f.Close()
img, _, err := image.Decode(bufio.NewReader(f))
check(err)
pixels, err := getPixels(img)
check(err)
// Logic with pixels.
Теперь функция getPixels выглядит так:
func getPixels(img image.Image) ([]uint8, error) {
if i, ok := img.(*image.NRGBA); ok {
return i.Pix, nil
} else if i, ok := img.(*image.Alpha); ok {
return i.Pix, nil
} else if i, ok := img.(*image.Alpha16); ok {
return i.Pix, nil
} else if i, ok := img.(*image.CMYK); ok {
return i.Pix, nil
} else if i, ok := img.(*image.Gray); ok {
return i.Pix, nil
} else if i, ok := img.(*image.Gray16); ok {
return i.Pix, nil
} else if i, ok := img.(*image.NRGBA64); ok {
return i.Pix, nil
} else if i, ok := img.(*image.Paletted); ok {
return i.Pix, nil
} else if i, ok := img.(*image.RGBA); ok {
return i.Pix, nil
} else if i, ok := img.(*image.RGBA64); ok {
return i.Pix, nil
}
return nil, fmt.Errorf("unknown image type %T", img)
}
Но я думаю, что это безобразно. Голанг знает тип изображения, и я бы предпочел что-то вроде этого:
func getPixels(img image.Image) ([]uint8, error) {
if i, ok := img.(eval(fmt.Sprintf("%T", img))); ok {
return i.Pix, nil
}
return nil, fmt.Errorf("unknown image type %T", img)
}
Я тоже не могу утверждать reflect.TypeOf(img)
, Может быть, есть способ получить тип из reflect.Type
интерфейс?
1 ответ
Ваш большой if ... else
структуру можно упростить, используя переключатель типа, например так:
func getPixels(img image.Image) ([]uint8, error) {
switch i := img.(type) {
case *image.NRGBA:
return i.Pix, nil
case *image.Alpha:
return i.Pix, nil
case *image.Alpha16:
return i.Pix, nil
case *image.CMYK:
return i.Pix, nil
// ...
}
return nil, fmt.Errorf("unknown image type %T", img)
}
Где вам еще нужно перечислить все возможные типы, но это лучше.
Поскольку все реализации изображений являются указателями структуры, имеющими поле с именем Pix
Вы можете использовать отражение, чтобы получить это поле. Эта реализация будет обрабатывать будущие реализации изображений без каких-либо изменений (если они также будут структурированы с Pix
поле).
Вот как это будет выглядеть:
func getPix(img image.Image) ([]uint8, error) {
v := reflect.ValueOf(img)
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
if v.Kind() == reflect.Struct {
pv := v.FieldByName("Pix")
if pv.IsValid() {
if pix, ok := pv.Interface().([]uint8); ok {
return pix, nil
}
}
}
return nil, fmt.Errorf("unknown image type %T", img)
}
Тестирование это:
fmt.Println(getPix(&image.NRGBA{}))
fmt.Println(getPix(&image.RGBA{}))
type unknownImage struct{ image.Image }
fmt.Println(getPix(unknownImage{}))
Вывод (попробуйте на Go Playground):
[] <nil>
[] <nil>
[] unknown image type main.unknownImage