Golang:给定其值的常量的名称

时间:2013-10-03 09:02:20

标签: go

如何获得常量的名称?

更具体地说(为了获得更易读的理解),我正在使用crypto/tls包。密码套件定义为常量:

const (
    TLS_RSA_WITH_RC4_128_SHA            uint16 = 0x0005
    TLS_RSA_WITH_3DES_EDE_CBC_SHA       uint16 = 0x000a
    TLS_RSA_WITH_AES_128_CBC_SHA        uint16 = 0x002f
    TLS_RSA_WITH_AES_256_CBC_SHA        uint16 = 0x0035
    TLS_ECDHE_RSA_WITH_RC4_128_SHA      uint16 = 0xc011
    TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0xc012
    TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA  uint16 = 0xc013
    TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA  uint16 = 0xc014
)

与服务器成功握手后,我可以通过连接与Ciphersuite达成协议:

c, _ := tls.Dial("tcp", "somedomain.com:443", nil)
// Suppose everything went right

// This is the Ciphersuite for the conn:
cipher := c.ConnectionState().Ciphersuite

cipher这是一个uint16。有没有办法将其显示为字符串,例如TLS_RSA_WITH_3DES_EDE_CBC_SHA,如果这是商定的内容?

3 个答案:

答案 0 :(得分:22)

注意:从Go 1.4开始,下面的String()代码可以使用Go的新generate功能自动生成,并结合stringer命令。 See here了解更多信息。

除了ANisus的回答,您可以执行以下操作。

package main

import "fmt"
import "crypto/tls"

type Ciphersuite uint16

const (
    TLS_RSA_WITH_RC4_128_SHA            = Ciphersuite(tls.TLS_RSA_WITH_RC4_128_SHA)
    TLS_RSA_WITH_3DES_EDE_CBC_SHA       = Ciphersuite(tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA)
    TLS_RSA_WITH_AES_128_CBC_SHA        = Ciphersuite(tls.TLS_RSA_WITH_AES_128_CBC_SHA)
    TLS_RSA_WITH_AES_256_CBC_SHA        = Ciphersuite(tls.TLS_RSA_WITH_AES_256_CBC_SHA)
    TLS_ECDHE_RSA_WITH_RC4_128_SHA      = Ciphersuite(tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA)
    TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA = Ciphersuite(tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA)
    TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA  = Ciphersuite(tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA)
    TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA  = Ciphersuite(tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA)
)

func (cs Ciphersuite) String() string {
    switch cs {
    case TLS_RSA_WITH_RC4_128_SHA:
        return "TLS_RSA_WITH_RC4_128_SHA"
    case TLS_RSA_WITH_3DES_EDE_CBC_SHA:
        return "TLS_RSA_WITH_3DES_EDE_CBC_SHA"
    case TLS_RSA_WITH_AES_128_CBC_SHA:
        return "TLS_RSA_WITH_AES_128_CBC_SHA"
    case TLS_RSA_WITH_AES_256_CBC_SHA:
        return "TLS_RSA_WITH_AES_256_CBC_SHA"
    case TLS_ECDHE_RSA_WITH_RC4_128_SHA:
        return "TLS_ECDHE_RSA_WITH_RC4_128_SHA"
    case TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA:
        return "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA"
    case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:
        return "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA"
    case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
        return "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA"
    }
    return "Unknown"
}

func main() {
    cs := TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA
    fmt.Printf("0x%04x = %s\n", uint16(cs), cs)

    cs = TLS_RSA_WITH_RC4_128_SHA
    fmt.Printf("0x%04x = %s\n", uint16(cs), cs)

    cs = TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
    fmt.Printf("0x%04x = %s\n", uint16(cs), cs)
}

您可以在go playground上进行测试。

答案 1 :(得分:15)

我担心这是不可能的。
常量在编译时解析,reflect包中没有任何内容允许您检索名称。

我建议创建一个名称为

的地图
var constLookup = map[uint16]string{
    tls.TLS_RSA_WITH_RC4_128_SHA:      `TLS_RSA_WITH_RC4_128_SHA`,
    tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA: `TLS_RSA_WITH_3DES_EDE_CBC_SHA`,
    ...
}

答案 2 :(得分:7)

您可以使用go generate为您生成此内容。

使用

安装stringer
go get golang.org/x/tools/cmd/stringer

现在为type定义const。你可以这样做

type TLSType uint16
const (
    TLS_RSA_WITH_RC4_128_SHA            TLSType = 0x0005
    TLS_RSA_WITH_3DES_EDE_CBC_SHA       TLSType = 0x000a
    TLS_RSA_WITH_AES_128_CBC_SHA        TLSType = 0x002f
    TLS_RSA_WITH_AES_256_CBC_SHA        TLSType = 0x0035
    TLS_ECDHE_RSA_WITH_RC4_128_SHA      TLSType = 0xc011
    TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA TLSType = 0xc012
    TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA  TLSType = 0xc013
    TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA  TLSType = 0xc014
)

然后将此行添加到您的文件中(间距很重要)

//go:generate stringer -type=TLSType

现在转到程序所在文件夹中的终端并运行

go generate

这将在您的代码目录中创建一个名为tlstype_string.go的文件,该文件是为fmt.Stringer实现TLSType接口的生成代码。如果您想查看实施但是不需要,请打开它。它会起作用。

现在,当您在此目录上运行go buildgo run *.go时,您的源文件将使用生成的代码。

完整的程序看起来像这样

package main

import (
    "fmt"
)

//go:generate stringer -type=TLSType
type TLSType uint16

const (
    TLS_RSA_WITH_RC4_128_SHA            TLSType = 0x0005
    TLS_RSA_WITH_3DES_EDE_CBC_SHA       TLSType = 0x000a
    TLS_RSA_WITH_AES_128_CBC_SHA        TLSType = 0x002f
    TLS_RSA_WITH_AES_256_CBC_SHA        TLSType = 0x0035
    TLS_ECDHE_RSA_WITH_RC4_128_SHA      TLSType = 0xc011
    TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA TLSType = 0xc012
    TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA  TLSType = 0xc013
    TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA  TLSType = 0xc014
)

func main() {
    fmt.Println("This const will be printed with its name instead of its number:")
    fmt.Println(TLS_RSA_WITH_RC4_128_SHA)
    fmt.Println()
    fmt.Println("So will this one:")
    fmt.Println(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA)
    fmt.Println()
    fmt.Println("Or maybe we want to give it a value and convert:")
    fmt.Println(TLSType(0xc011))
    fmt.Println()
    fmt.Println("No problem:")
    fmt.Println(TLSType(0xc013))
}

哪个输出

This const will be printed with its name instead of its number:
TLS_RSA_WITH_RC4_128_SHA

So will this one:
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA

Or maybe we want to give it a value and convert:
TLS_ECDHE_RSA_WITH_RC4_128_SHA

No problem:
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA

如果您添加新的const值,请再次运行go generate以更新生成的代码。