将接口断言为其类型
Assert interface to its type
在一般情况下,我无法优雅地将图像的像素作为数组获取。
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)
}
但我觉得这很难看。 Golang 知道图像的类型,我更喜欢这样的东西:
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
接口获取类型?
您的大型 if ... else
结构可以通过使用 type switch 来简化,如下所示:
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
在一般情况下,我无法优雅地将图像的像素作为数组获取。
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)
}
但我觉得这很难看。 Golang 知道图像的类型,我更喜欢这样的东西:
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
接口获取类型?
您的大型 if ... else
结构可以通过使用 type switch 来简化,如下所示:
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