dongxie2756 2018-09-04 10:34
浏览 69
已采纳

将接口声明为其类型

I can't gracefully get pixels of an image as array in general case.

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.

Now function getPixels looks like this:

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)
}

But I think this is ugly. Golang knows type of image and I would prefer something like this:

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)
}

I also can't assert to reflect.TypeOf(img). Maybe there is a way to get type from reflect.Type interface?

  • 写回答

1条回答 默认 最新

  • duanchuo7741 2018-09-04 10:46
    关注

    Your big if ... else structure could be simplified by using a type switch like this:

    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)
    }
    

    Where you still have to list all possible types, but it's nicer.

    Since all image implementations are struct pointers having a field named Pix, you may use reflection to get that field. This implementation will handle future image implementations without any change (if they will also be structs with a Pix field).

    This is how it would look like:

    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)
    }
    

    Testing it:

    fmt.Println(getPix(&image.NRGBA{}))
    fmt.Println(getPix(&image.RGBA{}))
    
    type unknownImage struct{ image.Image }
    fmt.Println(getPix(unknownImage{}))
    

    Output (try it on the Go Playground):

    [] <nil>
    [] <nil>
    [] unknown image type main.unknownImage
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 用lstm来预测股票价格
  • ¥15 请问paddlehub能支持移动端开发吗?在Android studio上该如何部署?
  • ¥170 如图所示配置eNSP
  • ¥20 docker里部署springboot项目,访问不到扬声器
  • ¥15 netty整合springboot之后自动重连失效
  • ¥15 悬赏!微信开发者工具报错,求帮改
  • ¥20 wireshark抓不到vlan
  • ¥20 关于#stm32#的问题:需要指导自动酸碱滴定仪的原理图程序代码及仿真
  • ¥20 设计一款异域新娘的视频相亲软件需要哪些技术支持
  • ¥15 stata安慰剂检验作图但是真实值不出现在图上