ENUMs for custom types in GO

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

ENUMs for custom types in GO

问题

我正在尝试为我定义的类型生成一个枚举。

type FeeStage int

这里我了解到可以使用iota基于这个类型创建一个枚举。

const (
    Stage1 FeeStage = iota
    Stage2
    Stage3
)

然而,操作枚举的实际值相当麻烦且容易出错。

const (
    Stage1 FeeStage = iota           // 0
    Stage2          = iota + 6       // 7
    Stage3          = (iota - 3) * 5 // -5
)

是否有一种方法可以自动将具有自定义值的ENUM列表转换为特定类型?之前我使用的方法只能将常量的第一个成员转换为自定义类型。

const (
    Stage1 FeeStage = 1
    Stage2          = 2
    Stage3          = 2
)

这里是一个类似结果的示例。

英文:

I am trying to generate an enum for a type I defined

type FeeStage int

From this I learned that I can use iota to create an enum based on this type

const(
     Stage1 FeeStage = iota
     Stage2 
     Stage3
)

However, manipulating the actual values of the enum is rather cumbersome and error prone

const(
     Stage1 FeeStage = iota           // 0
     Stage2          = iota + 6       // 7
     Stage3          = (iota - 3) * 5 // -5
)

Is there a way to automatically convert a list of ENUMs with custom values to a certain type. This is what I was using before but only converts the first member of the constant to the custom type.

const(
     Stage1 FeeStage = 1
     Stage2          = 2
     Stage3          = 2
)

Here is a playground with a similar result

答案1

得分: 8

没有其他方法,除非使用iota和自动枚举,或者做最直接的事情:

const (
    Stage1 FeeStage = 1
    Stage2 FeeStage = 2

    // 或者使用相同结果的另一种语法
    Stage3 = FeeStage(2)
)

在我看来,这比像iota + 5这样的操作要简单。

如果值在程序的上下文之外不重要,我通常使用iota,如果需要将值用于协议或其他用途,则使用显式类型。

不过我必须说,有时候只使用整数或字符串就足够了,这取决于上下文。例如,可以查看标准库中的HTTP状态码,它们没有特殊的类型。

英文:

There's no way beyond either using iota and automatic enums, or doing the most straightforward thing:

const(
     Stage1 FeeStage = 1
     Stage2 FeeStage = 2

     // or another syntax with same results
     Stage3 = FeeStage(2)
)

which IMHO is less cumbersome than doing stuff like iota + 5 which as you said is really bad.

I usually either use iota if the value is not important beyond the context of the program, or explicit typing if I need the values to be used in a protocol or something.

Though I have to say sometimes just using ints or strings is good enough, it depends on the context. See for example the http status codes in the standard library. They don't have a special type.

答案2

得分: 2

你可能需要澄清一下你实际想要对枚举常量做什么,但看起来你正在尝试为自定义类型分配任意值。

如果你将常量和初始化结构化并按照一定的模式进行排序,使用iota并不需要很麻烦。Effective Go也有相关的章节。

你可以为枚举常量创建相当复杂的模式,这样就不会出错且不会很麻烦。

英文:

You should maybe clarify what you're actually wanting to do with enumerated constants, but it looks like you're trying to assign arbitrary values to your custom type.

Using iota doesn't need to be cumbersome if you structure your constants and the initialization to be ordered and to follow a pattern. Effective Go has a section on this too.

You can create fairly complicated patterns for enumerated constants, which doesn't have to be error-prone and cumbersome.

答案3

得分: 1

实际上有一种方法。但是让我们先澄清一些事情。

在常量声明中,如果指定了类型,常量将采用指定的类型:

const n int64 = 3 // n将是一个有类型的常量,其类型为int64

如果省略了类型,常量将采用表达式的类型:

const x = int16(3) // x将是一个有类型的常量,其类型为int16

如果表达式是无类型常量,声明的常量将保持为无类型常量:

const i = 1 // i将是一个无类型整数常量

请注意,如果您尝试打印i的类型(例如使用fmt.Printf("%T", i)),您将看到int,这是因为当将常量传递给函数或将其赋值给变量时,它必须转换为实际的类型,并且将使用默认类型(因为fmt.Println()的参数类型为interface{})-对于无类型整数常量,默认类型为int

在括号中的const声明列表中,可以省略声明中的表达式列表(除了第一个)。如果省略了表达式,将使用先前的非空表达式(文本替换)。

所以当您这样做时:

const(
     Stage1 FeeStage = iota
     Stage2 
     Stage3
)

它的意思是:

const (
    Stage1 FeeStage = iota
    Stage2 FeeStage = iota
    Stage3 FeeStage = iota
)

这将产生3个新的常量:Stage1Stage2Stage3,它们都是类型为FreeStage的常量。

您的第二个示例:

const (
    Stage1 FeeStage = iota           // 0
    Stage2          = iota + 6       // 7
    Stage3          = (iota - 3) * 5 // -5
)

由于您没有省略表达式,只有第一个常量Stage1将是一个有类型的常量(类型为FreeStage),其余的将是无类型常量!所以这甚至不符合您的要求!

现在来谈谈您的问题:您想要这样的东西:

const(
     Stage1 FeeStage = 1
     Stage2          = 2
     Stage3          = 2
)

如上所述,如果省略类型,Stage2Stage3将是无类型常量。因此,必须指定类型,您可以利用常量规范的以下事实:

ConstSpec      = IdentifierList [ [ Type ] "=" ExpressionList ] .

您可以指定一个标识符_列表_:

const(
    Stage1, Stage2, Stage3 FeeStage = 1, 2, 2
)

这样更易读吗?也许如果只有几个常量。如果有很多,请使用Not_a_Golfer的建议:

const(
    Stage1 FeeStage = 1
    Stage2 FeeStage = 2
    Stage3 FeeStage = 2
)
英文:

Actually there's a way. But let's clear some things first.

In constant declarations, if the type is present, the constant will take the specified type:

const n int64 = 3 // n will be a typed constant, its type will be int64

If the type is omitted, the constant will take the type of the expression:

const x = int16(3) // x will be a typed constant, its type will be int16

If the expression is an untyped constant, the declared constant will remain untyped constant:

const i = 1 // i will be an untyped integer constant

Note that if you try to print i's type (e.g. with fmt.Printf("%T", i), you will see int, and that's because when passing a constant to a function or when assigning it to a variable, it has to be converted to an actual type, and the default type will be used (because fmt.Println() has arguments type of interface{}) - which is int for an untyped integer constant.

Within a parenthesized const declaration list the expression list may be omitted from declarations (except at the first). If the expression is missing, the previous non-empty expression will be used (textual substitution).

So when you do this:

const(
     Stage1 FeeStage = iota
     Stage2 
     Stage3
)

It means:

const (
    Stage1 FeeStage = iota
    Stage2 FeeStage = iota
    Stage3 FeeStage = iota
)

Which results in 3 new constants: Stage1, Stage2 and Stage3, all being of type FreeStage.

Your second example:

const (
    Stage1 FeeStage = iota           // 0
    Stage2          = iota + 6       // 7
    Stage3          = (iota - 3) * 5 // -5
)

Since you didn't omit the expressions, ONLY your first constant Stage1 will be a typed constant (of type FreeStage), the rest will be untyped constants! So this doesn't even qualify (doesn't comply with your requirements)!

And now to your point: you want something like this:

const(
     Stage1 FeeStage = 1
     Stage2          = 2
     Stage3          = 2
)

As stated above, if you leave out the type, Stage2 and Stage3 will be untyped constants. So type must be specified, you may take advantage of the fact that a const specification is:

ConstSpec      = IdentifierList [ [ Type ] "=" ExpressionList ] .

You may specify an identifier list:

const(
    Stage1, Stage2, Stage3 FeeStage = 1, 2, 2
)

Is this more readable? Maybe if there are a few constants only. If there are many, use Not_a_Golfer's recommendation:

const(
    Stage1 FeeStage = 1
    Stage2 FeeStage = 2
    Stage3 FeeStage = 2
)

huangapple
  • 本文由 发表于 2016年3月29日 23:39:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/36288890.html
匿名

发表评论

匿名网友

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

确定