>  기사  >  백엔드 개발  >  Go에서 Iota를 사용하는 방법

Go에서 Iota를 사용하는 방법

藏色散人
藏色散人앞으로
2021-04-29 11:52:432121검색

다음 튜토리얼 칼럼인 golang에서는 Go에서 Iota를 사용하는 방법을 소개하겠습니다. 도움이 필요한 친구들에게 도움이 되길 바랍니다!

소개

Go 언어는 실제로 열거형 키워드를 직접 지원하지 않습니다. 일반적으로 const + iota를 통해 열거 기능을 구현합니다. const + iota 实现枚举的能力。

有人要问了,为什么一定要使用枚举呢?stackoverflow 上有一个高赞的回答,如下:

You should always use enums when a variable (especially a method parameter) can only take one out of a small set of possible values. Examples would be things like type constants (contract status: “permanent”, “temp”, “apprentice”), or flags (“execute now”, “defer execution”). If you use enums instead of integers (or String codes), you increase compile-time checking and avoid errors from passing in invalid constants, and you document which values are legal to use.BTW, overuse of enums might mean that your methods do too much (it’s often better to have several separate methods, rather than one method that takes several flags which modify what it does), but if you have to use flags or type codes, enums are the way to go.

简单翻译一下, 两点很重要。

  • 当一个变量(尤其是方法参数) 只能从一小部分可能的值中取出一个时,理应使用枚举。
    例如类型常量(合同状态:永久、临时工、学徒), 或者在做任务程序时,是立即执行还是延迟执行的标记。
  • 如果使用枚举而不是整形,则会增加编译时的检查,避免错误无效值的传入,记录哪些值是合法使用的。

如何实现枚举

iota 是 Go 中预声明的一个特殊常量。它会被预声明为0,但是它的值在编译阶段并非是固定的,当预声明的 iota 出现在一个常量声明中的时候,它的值在第n个常量描述中的值为n(从0开始)。所以它只在同类型多个常量声明的情况下才显得有意义。

比如,大家都了解的电商,订单系统一定会涉及到订单状态的流转。那么这时候,我们一般可以这样做:

package mainimport "fmt"type OrderStatus intconst (
  Cancelled OrderStatus = iota //订单已取消 0  NoPay OrderStatus = iota //未支付  1  PendIng OrderStatus = iota // 未发货 2  Delivered OrderStatus = iota // 已发货 3  Received OrderStatus = iota // 已收货 4)func main() {
  fmt.Println(Cancelled, NoPay) // 打印:0,1}

当然,这样看着好麻烦。其实,其他常量可以重复上一行 iota 表达式,我们可以改成这样。

package mainimport "fmt"type OrderStatus intconst (
  Cancelled OrderStatus = iota //订单已取消 0  NoPay //未支付 1  PendIng // 未发货 2  Delivered // 已发货 3  Received // 已收货 4)func main() {
  fmt.Println(Cancelled, NoPay) // 打印:0,1}

有人会用 0 的值来表示状态吗?一般都不会,我们想以1开头,那么可以这样。

package mainimport "fmt"type OrderStatus intconst (
  Cancelled OrderStatus = iota+1 //订单已取消 1
  NoPay //未支付 2  PendIng // 未发货 3  Delivered // 已发货 4  Received // 已收货 5)func main() {
  fmt.Println(Cancelled, NoPay) // 打印:1,2}

我们还想在 Delivered 后跳过一个数字,才是 Received 的值,也就是 Received=6,那么可以借助 _ 符号。

package mainimport "fmt"type OrderStatus intconst (
  Cancelled OrderStatus = iota+1 //订单已取消 1
  NoPay //未支付 2  PendIng // 未发货 3  Delivered // 已发货 4  _
 Received // 已收货 6)func main() {
  fmt.Println(Received) // 打印:6}

顺着来可以,倒着当然也行。

package mainimport "fmt"type OrderStatus intconst (
  Max = 5)const (
  Received OrderStatus = Max - iota // 已收货  5  Delivered // 已发货 4  PendIng // 未发货 3  NoPay //未支付 2  Cancelled //订单已取消 1)func main() {
  fmt.Println(Received,Delivered) // 打印:5,4}

你还可以使用位运算,比如在 go 源码中的包 sync 中的锁上面有这么一段代码。

const (
 mutexLocked = 1 << iota  //1<<0 mutexWoken               //1<<1 mutexStarving            //1<<2 mutexWaiterShift = iota  //3
)

func main() {
 fmt.Println("mutexLocked的值",mutexLocked) //打印:1 fmt.Println("mutexWoken的值",mutexWoken) //打印:2 fmt.Println("mutexStarving的值",mutexStarving) //打印:4 fmt.Println("mutexWaiterShift的值",mutexWaiterShift) // 打印:3}

可能有人平常是直接定义常量值或者用字符串来表示的。

比如,上面这些我完全可以用 string 来表示,我还真见过用字符串来表示订单状态的。

package main

import "fmt"

const (
  Cancelled = "cancelled"  NoPay = "noPay"  PendIng = "pendIng"  Delivered = "delivered"  Received = "received")

var OrderStatusMsg = map[string]string{
  Cancelled: "订单已取消",
  NoPay:     "未付款",
  PendIng:   "未发货",
  Delivered: "已发货",
  Received:  "已收货",
}

func main() {
  fmt.Println(OrderStatusMsg[Cancelled])
}

或者直接定义整形常量值。

package main

import "fmt"

const (
  Cancelled = 1  NoPay = 2  PendIng = 3  Delivered = 4  Received = 5)

var OrderStatusMsg = map[int]string{
  Cancelled: "订单已取消",
  NoPay:     "未付款",
  PendIng:   "未发货",
  Delivered: "已发货",
  Received:  "已收货",
}

func main() {
  fmt.Println(OrderStatusMsg[Cancelled])
}

其实上述两种都可以,但是相比之下使用 iota 更有优势。

  • 能保证一组常量的唯一性,人工定义的不能保证。
  • 可以为一组动作分享同一种行为。
  • 避免无效值。
  • 提高代码阅读性以及维护。

延伸

按照上面我们所演示的,最后我们可以这样操作。

package main

import (
 "fmt")

type OrderStatus int

const (
  Cancelled OrderStatus = iota + 1 //订单已取消 1  NoPay //未支付 2  PendIng // 未发货 3  Delivered // 已发货 4  Received // 已收货 5)

//公共行为 赋予类型 String() 函数,方便打印值含义
func (order OrderStatus) String() string { return [...]string{"cancelled", "noPay", "pendIng", "delivered", "received"}[order-1]
}

//创建公共行为 赋予类型 int 函数 EnumIndex()
func (order OrderStatus) EnumIndex() int { return int(order)
}

func main() {
 var order OrderStatus = Received
  fmt.Println(order.String())    // 打印:received
  fmt.Println(order.EnumIndex()) // 打印:5
}

总结

这篇文章主要介绍了 Golang 中对 iota

왜 열거형을 사용해야 합니까?라고 묻는 사람이 있을 수 있습니다. stackoverflow에는 다음과 같이 매우 칭찬받는 답변이 있습니다.

변수(특히 메서드 매개변수)가 가능한 작은 값 집합 중 하나만 가져올 수 있는 경우 항상 열거형을 사용해야 합니다. 예를 들어 정수(또는 문자열 코드) 대신 열거형을 사용하는 경우 유형 상수(계약 상태: "영구", "임시", "견습생") 또는 플래그("지금 실행", "실행 연기") 등이 있습니다. ), 컴파일 타임 검사를 늘리고 유효하지 않은 상수 전달로 인한 오류를 방지하고 어떤 값을 사용하기에 적합한지 문서화합니다. 그런데 열거형을 과도하게 사용하면 메소드가 너무 많은 일을 한다는 것을 의미할 수 있습니다(여러 개의 별도의 값을 갖는 것이 더 나은 경우가 많습니다). 여러 플래그를 사용하여 기능을 수정하는 하나의 메서드가 아니라) 플래그나 유형 코드를 사용해야 하는 경우 열거형을 사용하는 것이 좋습니다.
간단한 번역, 두 가지 사항이 매우 중요합니다. . 🎜
  • 변수(특히 메소드 매개변수)가 소수의 가능한 값 중 하나만 취할 수 있는 경우 열거형을 사용해야 합니다.
    예를 들어 태스크 프로그램을 수행할 때 상수(계약 상태: 정규직, 임시직, 견습생)를 입력하거나 즉시 실행 또는 지연 실행을 위한 플래그를 입력합니다.
  • 정수 대신 열거형을 사용하는 경우 잘못된 잘못된 값이 전달되는 것을 방지하고 어떤 값이 합법적으로 사용되는지 기록하기 위해 컴파일 타임 검사가 추가됩니다.
🎜🎜🎜열거 구현 방법🎜🎜iota는 Go에서 미리 선언된 특수 상수입니다. 0으로 미리 선언되지만, 그 값은 컴파일 단계에서 고정되지 않습니다. 미리 선언된 iota가 상수 선언에 나타나면 그 값은 n번째 상수에 기술됩니다. (0부터 시작). 따라서 동일한 유형의 상수 선언이 여러 개 있는 경우에만 의미가 있습니다. 🎜🎜예를 들어 전자상거래에 대해서는 누구나 알고 있듯이 주문 시스템에는 반드시 주문 상태의 흐름이 포함됩니다. 따라서 현재로서는 일반적으로 다음과 같이 할 수 있습니다. 🎜rrreee🎜물론 이것은 매우 번거로워 보입니다. 실제로 다른 상수는 이전 줄의 iota 표현식을 반복할 수 있으며 이를 이렇게 변경할 수 있습니다. 🎜rrreee🎜누구나 0 값을 사용하여 상태를 나타낼 수 있나요? 일반적으로 그렇지 않습니다. 우리는 1부터 시작하고 싶으므로 괜찮습니다. 🎜rrreee🎜또한 Received의 값인 Delivered 뒤의 숫자, 즉 Received=6를 건너뛰고 싶습니다. _ 기호를 사용할 수 있습니다. 🎜rrreee🎜길따라 해도 괜찮고, 거꾸로 해도 당연히 괜찮습니다. 🎜rrreee🎜비트 연산을 사용할 수도 있습니다. 예를 들어 Go 소스 코드의 sync 패키지에 있는 잠금 장치에 이러한 코드가 있습니다. 🎜rrreee🎜아마도 어떤 분들은 보통 상수 값을 직접 정의하거나 문자열을 사용하여 표현하는 경우가 많을 것입니다. 🎜🎜예를 들어 string을 사용하여 위 내용을 나타낼 수 있습니다. 실제로 주문 상태를 나타내는 데 사용되는 문자열을 본 적이 있습니다. 🎜rrreee🎜또는 정수 상수 값을 직접 정의하세요. 🎜rrreee🎜사실 위 두가지 모두 가능하지만 iota를 사용하면 더 많은 장점이 있습니다. 🎜
  • 상수 집합의 고유성은 보장할 수 있지만 수동 정의는 보장할 수 없습니다.
  • 동일한 동작이 작업 그룹에 대해 공유될 수 있습니다.
  • 잘못된 값을 피하세요.
  • 코드 가독성과 유지 관리가 향상됩니다.
🎜🎜🎜Extension🎜🎜 위에서 설명한 내용을 따르면 마침내 이를 수행할 수 있습니다. 🎜rrreee🎜Summary🎜🎜이 글에서는 주로 Golang에서 iota를 사용하는 방법과 이를 사용해야 하는 이유를 소개합니다. 🎜🎜이런 장면에서 주로 어떤 트릭을 사용하시는지 모르겠네요. 교환을 원하시면 아래 메시지를 남겨주세요. ㅋㅋㅋ

위 내용은 Go에서 Iota를 사용하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 learnku.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제