关于type之后的类型作为case的一种情况的类型检查 发现出错

GuoYuefei · 2018-10-27 22:51:52 · 845 次点击 · 大约8小时之前 开始浏览    置顶
这是一个创建于 2018-10-27 22:51:52 的主题,其中的信息可能已经有所发展或是发生改变。

以下代码在类型检查那边会出错,只会执行default的。但是在简单的代码中我试验过了可以使用这种type之后的类型作为case的一种情况的

type CBC func(b cipher.Block, iv []byte) cipher.BlockMode
type CFB func(b cipher.Block, iv []byte) cipher.Stream

type ModeFunc string

const (
    CBCDecrypter ModeFunc = "NewCBCDecrypter"
    CBCEncrypter ModeFunc = "NewCBCEncrypter"

    CFBDecrypter ModeFunc = "NewCFBDecrypter"
    CFBEncrypter ModeFunc = "NewCFBEncrypter"
)

//接下来就是将这两种不同模式下的aes加密写成一个函数
func AESCrypt(word, key, iv []byte, modeFunc ModeFunc) []byte {

    CheckKey(key)
    funcs := map[ModeFunc] interface{} {
        CBCEncrypter: cipher.NewCBCEncrypter,
        CBCDecrypter: cipher.NewCBCDecrypter,
        CFBDecrypter: cipher.NewCFBDecrypter,
        CFBEncrypter: cipher.NewCFBEncrypter,
    }

    block, err := aes.NewCipher(key)
    if err != nil {
        panic(err)
    }

    //得先判定加密还是解密
    if modeFunc == CBCEncrypter || modeFunc == CFBEncrypter {
        word = PKCS7Padding(word, block.BlockSize())
    }

    result := make([]byte, len(word))

    //bug 类型检查为什么会运行到default。。。   查到了。
    //不用type类型的时候是可以识别的 但是为什么用type之后的别名识别不了呢
    //查了下资料,资料显示 type和c/c++中的typedef是不一样的
    //type之后产生的类型只继承了原有类型的所有元素 但是不包括函数
    //所以两个类型是不对等的  其实有些奇怪为什么在上面函数中map的value类型为什么能直接使用type之后的类型而且不出问题
    //而且事实上我在某个地方类型检查是使用过type类型,并没有出问题
    switch fun := funcs[modeFunc].(type) {
    case CBC:
        blockMode := fun(block, iv)
        blockMode.CryptBlocks(result, word)
    case CFB:
        blockMode := fun(block, iv)
        blockMode.XORKeyStream(result, word)
    default:
        fmt.Println("something wrong!")
    }
    if modeFunc == CBCDecrypter || modeFunc == CFBDecrypter {
        result = PKCS7UnPadding(result)
    }
    return result
}

之前我用一个简单的文件检查过这种方法能实施的,但是到这里就出错了。必须要把函数原型原封不动的写出来才能正常执行。 switch改成这样才是正确的。但是我无法理解为什么上面的方式是不对的

switch fun := funcs[modeFunc].(type) {
    case func(b cipher.Block, iv []byte) cipher.BlockMode:
        blockMode := fun(block, iv)
        blockMode.CryptBlocks(result, word)
    case func(b cipher.Block, iv []byte) cipher.Stream:
        blockMode := fun(block, iv)
        blockMode.XORKeyStream(result, word)
    default:
        fmt.Println("something wrong!")
    }

还有以下代码也是成立的,证明map的value的类型使用type之后的类型也是可以的。

func AESCBCCrypt(word, key, iv []byte, modeFunc ModeFunc) []byte {
    funcs := map[ModeFunc]NewCBCCipherModel{
        CBCEncrypter: cipher.NewCBCEncrypter,
        CBCDecrypter: cipher.NewCBCDecrypter,
    }
    //检查key的合法性
    CheckKey(key)
    block, err := aes.NewCipher(key)
    if err != nil {
        panic(err)
    }
    blockSize := block.BlockSize()

    //若处于加密模式,就先加补码否则在这就啥也不动
    if modeFunc == CBCEncrypter {
        //加上补码确保word是aes.blockSize的整倍数
        word = PKCS7Padding(word, blockSize)
    }

    blockMode := funcs[modeFunc](block, iv)

    result := make([]byte, len(word))

    blockMode.CryptBlocks(result, word)
    //处于解码模式的时候 结果去补码
    if modeFunc == CBCDecrypter {
        result = PKCS7UnPadding(result)
    }
    return result
}

我在这就搞不懂第一块代码的问题所在了,虽然能用第二种写法解决问题但是无法理解其中的错误。还望高手能够从细节方面给出简答。再次感谢!!!


有疑问加站长微信联系(非本文作者)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

845 次点击  
加入收藏 微博
3 回复  |  直到 2018-11-08 15:46:47
luojh2015
luojh2015 · #1 · 6年之前

go 中的type这种用法是重新定义了一个类型 type CBC func(b cipher.Block, iv []byte) cipher.BlockMode;而类型别名这个特性在golang1.9中引入,用法是type name = string;前一种就如下两个类一般,他们有相同的内部结构但类型判断时不是同一个类型。 class A{ a int; b int; }; class B{ a int; b int; };

luojh2015
luojh2015 · #2 · 6年之前

image.png image.png

GuoYuefei
GuoYuefei · #3 · 6年之前
luojh2015luojh2015 #1 回复

go 中的type这种用法是重新定义了一个类型 type CBC func(b cipher.Block, iv []byte) cipher.BlockMode;而类型别名这个特性在golang1.9中引入,用法是type name = string;前一种就如下两个类一般,他们有相同的内部结构但类型判断时不是同一个类型。 class A{ a int; b int; }; class B{ a int; b int; };

非常感谢回复,的确解决了我的疑问。点赞👍。原来声明别名是需要加等号的,以前没注意,非常感谢。

添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传