给定一个常量的值,求其名称。

huangapple go评论93阅读模式
英文:

Name of a constant given its value

问题

如何根据常量的值获取其名称?

更具体地说(为了更好地理解),我正在使用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
)

在与服务器成功握手之后,我可以通过连接获取协商的密码套件:

c, _ := tls.Dial("tcp", "somedomain.com:443", nil)
// 假设一切顺利

// 这是连接的密码套件:
cipher := c.ConnectionState().Ciphersuite

这里的cipher是一个uint16类型的值。是否有办法将其显示为字符串,例如,如果协商的密码套件是TLS_RSA_WITH_3DES_EDE_CBC_SHA,那么能否将其显示为该字符串?

英文:

How do you get the name of a constant given its value ?

More specifically (and to get a more readable understanding), I'm working with the crypto/tls package. Cipher suites are defined as constants:

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
)

After a successful handshake with a server, I can get to the Ciphersuite agreed on through the connection:

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

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

cipher here is an uint16. Is there a way to display it as a string, for instance TLS_RSA_WITH_3DES_EDE_CBC_SHA if that's what was agreed upon ?

答案1

得分: 32

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

除了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上测试它。

英文:

Note: As of Go 1.4, the String() code below can be auto-generated using Go's new generate feature, combined with the stringer command. See here for more info.

Apart from ANisus' answer, you can do the following.

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

You can test it on the go playground.

答案2

得分: 24

很抱歉,我不能提供代码翻译服务。但是,我可以帮你解释这段代码的含义。

这段代码中,作者想要获取常量的名称。然而,在编译时,常量的值已经被解析,而reflect包中没有提供任何方法来获取常量的名称。

作者建议创建一个包含常量名称的映射(map),以便在需要时进行查找。示例代码如下:

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`,
    ...
}

通过使用这个映射,你可以通过常量的值来获取对应的名称。

英文:

I am afraid that is not possible.
The constants are resolved at compile time and there is nothing in the reflect package that allows you to retrieve the name.

What I suggest is creating a map with the names:

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`,
	...
}

答案3

得分: 24

你可以使用go generate来自动生成代码。

首先使用以下命令安装stringer

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

然后定义一个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的文件,这个文件是为你的TLSType类型实现了fmt.Stringer接口的生成代码。如果你想查看实现细节,可以打开这个文件,但这不是必需的,它会自动工作。

现在当你在该目录下运行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("这个const将会以它的名称而不是它的数值打印出来:")
	fmt.Println(TLS_RSA_WITH_RC4_128_SHA)
	fmt.Println()
	fmt.Println("这个也是一样:")
	fmt.Println(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA)
	fmt.Println()
	fmt.Println("或者我们想给它一个值并进行转换:")
	fmt.Println(TLSType(0xc011))
	fmt.Println()
	fmt.Println("没有问题:")
	fmt.Println(TLSType(0xc013))
}

运行结果如下:

这个const将会以它的名称而不是它的数值打印出来:
TLS_RSA_WITH_RC4_128_SHA

这个也是一样:
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA

或者我们想给它一个值并进行转换:
TLS_ECDHE_RSA_WITH_RC4_128_SHA

没有问题:
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA

如果你添加了新的const值,只需再次运行go generate命令来更新生成的代码。

英文:

You can use go generate to have this generated for you.

Install stringer using

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

Now define a type for your const. You can do it like this

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
)

Then add this line to your file (spacing is important)

//go:generate stringer -type=TLSType

Now go to the terminal in the folder where your program is and run

go generate

This will create a file called tlstype_string.go in your code directory, which is the generated code that implements the fmt.Stringer interface for your TLSType. Open it if you want to see the implementation but you don't need to. It will just work.

Now when you run go build or go run *.go on this directory, your source files will use the generated code.

The full program would look something like this

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

Which outputs

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

If you add new const values, just run go generate again to update the generated code.

huangapple
  • 本文由 发表于 2013年10月3日 17:02:19
  • 转载请务必保留本文链接:https://go.coder-hub.com/19155038.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定