用iota枚举字符串常量

问题描述 投票:1回答:2

以下示例使用iota定义从3333开始的一系列端口号。

package main

import (
    "fmt"
)
const (
FirstPort = iota+3333
SecondPort
ThirdPort
)
func main() {
    hostAndPort := "localhost:"+fmt.Sprint(SecondPort)
    fmt.Printf("%s", hostAndPort ) 
    // Output:
    // localhost:3334
}

当组合主机名和端口时,我想避免在fmt.Sprint中包装端口常量并简单地写入,例如,"localhost:"+SecondPort。有没有办法使用iota将端口号定义为字符串常量,例如"3334"

以下不起作用:

FirstPort = string(iota + 3333)

也没有

FirstPort = fmt.Sprintf("%d", iota + 3333)
string go constants enumeration iota
2个回答
4
投票

引自Spec: Iota:

constant declaration中,预先声明的标识符iota表示连续的无类型整数constants

所以iota为你提供整数常量。如果我们想要string常数,我们需要找到一种方法将整数转换为其基数-10 string表示。这种方式必须是constant expression,否则我们不能在常量声明中使用它。

对我们来说不幸的是,从整数到conversion的简单类型string不会产生数值的基数10表示,但是:

将有符号或无符号整数值转换为字符串类型会生成包含整数的UTF-8表示形式的字符串。

因此结果将是一个持有单个符文的string,其值(Unicode代码点)是源编号。

同样调用“转换器”函数,如strconv.Itoa()fmt.Sprint()是不可能的,因为调用这些函数不能成为常量表达式的一部分,因此结果只能用于变量声明(更不用说我们不能使用iota) ,它只允许在常量声明中)。

但仍有解决方案。

我认为这不值得麻烦和可读性的损失,但实际上你可以使用string定义持有增加的十进制数的iota常量。

该解决方案从数字构建“完整”数字。我们可以通过连接数字的数字(作为string值)来获得base-10 string表示。

要解决的最后一个问题是如何“列出”数字的数字。这是一个简单的算术:

  • 数字的最后一位(在基数10中)是i % 10
  • 前面的数字是i / 10 % 10
  • 之前的那个是i / 100 % 10
  • 等等...

要获得rune的数字(在0..9的范围内),我们可以简单地添加'0',并将其转换为string。就这样。

这就是我们如何为1位数字符串编码编码:

n0 = string('0'+iota%10)

对于2位数字:

n00 = string('0'+iota/10%10) + string('0'+iota/1%10)

对于3位数字:

n000 = string('0'+iota/100%10) + string('0'+iota/10%10) + string('0'+iota/1%10)

让我们看看它的实际效果:

const (
    P00 = string('0'+iota/10%10) + string('0'+iota/1%10)
    P01
    P02
    P03
    P04
    P05
    P06
    P07
    P08
    P09
    P10
    P11
    P12
    P13
    P14
    P15
    P16
    P17
    P18
    P19
    P20
)

打印结果:

fmt.Printf("%v\n%v\n%v\n%v\n%v\n%v\n%v\n%v\n%v\n%v\n%v\n%v\n%v\n%v\n%v\n%v\n%v\n%v\n%v\n%v\n%v\n",
    P00, P01, P02, P03, P04, P05, P06, P07, P08, P09,
    P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20)

输出(在Go Playground上试试):

00
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20

到目前为止一切顺利,但我们如何从3333开始呢?

也不是问题,可以轻松实现。我们可以简单地通过添加“初始”数字来移动iota。这就是全部。

让我们看一个第一个数字是3339的例子:

const (
    P3339 = string('0'+(iota+3339)/1000%10) +
        string('0'+(iota+3339)/100%10) +
        string('0'+(iota+3339)/10%10) +
        string('0'+(iota+3339)/1%10)
    P3340
    P3341
)

func main() {
    fmt.Println(P3339)
    fmt.Println(P3340)
    fmt.Println(P3341)
}

以上的输出是预期的(尝试在Go Playground):

3339
3340
3341

1
投票

您正在创建无类型数字常量。如有疑问,请查看the spec。要创建一个包含主机和端口号的字符串,您可以像这样简单地使用fmt.Sprintf

package main

const (
    FirstPort = iota+3333
    SecondPort
    ThirdPort
)

func main() {
    hostPort := fmt.Sprintf("localhost:%d", FirstPort)
    fmt.Println(hostPort)
}

这就是它的全部:Demo

© www.soinside.com 2019 - 2024. All rights reserved.