当前位置: 首页 > 面试题库 >

将接口声明为其类型

从智志
2023-03-14
问题内容

一般情况下,我无法优雅地获取图像像素作为数组。

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通过使用如下所示的类型开关,可以简化大型结构:

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


 类似资料:
  • 问题内容: 将接口声明为抽象有什么意义?接口方法也是如此。有什么意义吗? 例如。 问题答案: 您在哪里遇到过已发布的代码块,任何旧的Java代码库? 这就是 JLS不得不说: 9.1.1.1抽象接口: 每个接口都是隐式抽象的。该修饰符已过时,不应在新程序中使用。 9.4抽象方法声明: 为了与Java平台的较早版本兼容,出于风格考虑,允许但不鼓励为接口中声明的方法冗余地指定abstract修饰符。

  • 问题内容: 为什么我们要在Java类中声明一个接口? 例如: 问题答案: 当您想在对象中收集一些字段以强调概念时,可以创建一个外部类,也可以创建一个内部类(称为嵌套(静态)或内部)。 如果要强调这个合作类在原始对象使用之外完全没有意义(没有用)的事实,可以将其嵌套/内部。 因此,在处理某些层次结构时,可以描述一个“嵌套” ,它将由包装类的子类实现。 在JDK中,最显著的例子是内部接口中定义的接口,

  • 问题内容: 在正确掌握接口最佳实践的过程中,我注意到一些声明,例如: 代替 -据我所知,原因是因为它有一定的灵活性,以防万一你不想实现ArrayList,但又可能实现另一种类型的列表。 通过这种逻辑,我建立了一个示例: 我的问题是,我无法访问batheSelf()方法,因为它仅适用于Cat。这使我相信,仅在使用接口中声明的方法时才应从接口声明(而不是子类中的其他方法),否则应直接从类中声明(在本例

  • 问题内容: 我注意到有些人喜欢将对象声明为它实现的接口之一, 即使在变量的范围内,也不必将其视为接口 ,例如,没有期望接口的外部API。 例如: 或者你可以做 并避免完全导入。 与类本身(第二个)相反,通过接口(上面的第一个)声明它有什么好处? 谢谢 问题答案: 如果以后不使用该变量,则没有优点/缺点。使用接口而不是对象的原因是为了提供更大的灵活性,但是,如果不使用该变量,则与性能方面没有什么区别

  • 我正在使用typescript,无法使用其他文件中声明的接口 我的看起来像这样。 下面是tsconfig.json 目录结构如下所示 在< code>common.ts文件中使用它

  • 问题内容: 有时我们有几个类,这些类的某些方法具有相同的签名,但是与声明的Java接口不对应。例如,和(在中的其他几个 )中都有一个方法 现在,假设我希望对具有该方法的对象进行一些操作。然后,我想有一个接口(或者自己定义),例如 这样我可以写: 但是,可悲的是,我不能: 此演员表将是非法的。编译器 知道 这 是不是 一个,因为类没有宣布实现该接口...... 然而“实际上”实现它 。 有时这会带来