ZetCode

Groovy 枚举

最后修改于 2025 年 3 月 20 日

Groovy 中的枚举定义了一组固定的常量,提高了代码的可读性和类型安全性。它们建立在 Java 的枚举基础上,但支持额外的功能,如自定义方法和 Groovy 特有的语法。本教程将通过示例探索枚举的基础知识和高级用法。

简单枚举

枚举使用 enum 关键字创建,以简洁、类型安全的方式列出常量,非常适合预定义的类别。

SimpleEnum.groovy
enum Color {
    RED, GREEN, BLUE
}

println Color.RED

Color 定义了三个常量。Color.RED 直接访问其中一个,打印 "RED"。枚举是隐式的静态 final,确保这些值在程序中保持不变。

带变量的枚举

枚举可以包含实例变量,通过构造函数初始化,为每个常量添加名称以外的数据。

EnumWithVars.groovy
enum Direction {
    NORTH(0), EAST(90), SOUTH(180), WEST(270)

    int degrees
    Direction(int deg) { degrees = deg }
}

println Direction.NORTH.degrees
println Direction.WEST.degrees

Direction 将每个常量与角度配对。degrees 通过构造函数设置,因此 Direction.NORTH.degrees 为 0,WEST.degrees 为 270。这表明枚举可以封装相关数据。

序数和值

枚举提供了内置方法,如用于位置的 ordinal 和用于所有常量的 values,这些方法对于迭代和索引很有用。

EnumOrdinalValues.groovy
enum Size {
    SMALL, MEDIUM, LARGE
}

println Size.SMALL

Size.each { println it }
Size.each { println "${it} ${it.ordinal()}" }

println Size.values()

Size.SMALL 打印 "SMALL",这是第一个常量。each 遍历所有大小,首先列出它们,然后使用 ordinal 显示它们的零基位置(SMALL: 0, MEDIUM: 1, LARGE: 2)。values 返回一个包含所有常量的数组,方便批量访问或转换为其他集合。

字符串强制转换

Groovy 允许隐式或显式地将字符串转换为枚举值,利用其灵活的类型系统简化枚举处理。

EnumStringCoercion.groovy
enum State {
    up,
    down
}

println State.up == 'up' as State
println State.down == 'down' as State

State s1 = 'up'
State s2 = 'down'

println State.up == s1
println State.down == s2

'up' as State 将 "up" 显式强制转换为 State.up,两个比较都返回 true。将 'up' 赋值给 s1 会隐式转换它,使其与 State.up 匹配。此功能简化了将字符串解析为枚举的过程,但大小写必须与枚举名称完全匹配。

自定义方法

枚举可以定义自定义方法,静态或实例方法,将其功能扩展到简单的常量之外,包含逻辑。

EnumCustomMethod.groovy
import java.util.Random

def season = Season.randomSeason()

String msg = switch (season) {
    case Season.SPRING -> "Spring"
    case Season.SUMMER -> "Summer"
    case Season.AUTUMN -> "Autumn"
    case Season.WINTER -> "Winter"
}

println(msg)

enum Season {
    SPRING,
    SUMMER,
    AUTUMN,
    WINTER;

    static Season randomSeason() {
        def random = new Random()
        int ridx = random.nextInt(Season.values().length)
        Season.values()[ridx]
    }
}

randomSeason 是一个静态方法,它使用 values 和随机索引返回一个随机的 Season 常量。switch 表达式将结果映射到友好的字符串。输出各不相同(例如,“Autumn”),显示了枚举如何封装行为,此处模拟了一个随机季节选择器。

Switch 表达式范围

枚举与 Groovy 的 switch 表达式无缝配合,包括范围和多个 case,使其在控制流中非常强大。

EnumSwitchRanges.groovy
enum Day {
    Monday,
    Tuesday,
    Wednesday,
    Thursday,
    Friday,
    Saturday,
    Sunday
}

def isWeekend(Day d) {
    switch (d) {
        case Day.Monday..Day.Friday -> false 
        case Day.Saturday, Day.Sunday -> true
    }
}

def days = [ Day.Monday, Day.Tuesday, Day.Wednesday, Day.Thursday, 
    Day.Friday, Day.Saturday, Day.Sunday ]

for (e in days) {
    if (isWeekend(e)) {
        println('weekend')
    } else {
        println('weekday')
    }
}

Day 列出了工作日。isWeekend 使用 switch 语句,对于工作日(Monday..Friday)使用范围(返回 false),对于周末使用逗号分隔列表(Saturday, Sunday,返回 true)。循环测试所有日期,打印五次“weekday”和两次“weekend”。这展示了 Groovy 在枚举中富有表现力的范围语法。

行星

枚举可以模拟具有属性和方法的复杂对象,例如具有质量和半径的行星,展示了它们的面向对象潜力。

EnumPlanets.groovy
double earthWeight = 63
double mass = earthWeight / Planet.EARTH.surfaceGravity()

for (Planet p : Planet.values()) {
    println("Your weight on ${p} is ${p.surfaceWeight(mass)}")
}

enum Planet {
    MERCURY (3.303e+23, 2.4397e6),
    VENUS   (4.869e+24, 6.0518e6),
    EARTH   (5.976e+24, 6.37814e6),
    MARS    (6.421e+23, 3.3972e6),
    JUPITER (1.9e+27,   7.1492e7),
    SATURN  (5.688e+26, 6.0268e7),
    URANUS  (8.686e+25, 2.5559e7),
    NEPTUNE (1.024e+26, 2.4746e7);

    private final double mass   // in kilograms
    private final double radius // in meters

    Planet(double mass, double radius) {
        this.mass = mass
        this.radius = radius
    }

    private double mass() { return mass }
    private double radius() { return radius }

    // universal gravitational constant (m3 kg-1 s-2)
    final double G = 6.67300E-11

    double surfaceGravity() {
        return G * mass / (radius * radius)
    }

    double surfaceWeight(double otherMass) {        
        return otherMass * surfaceGravity()
    }

    String toString() {
        name().toLowerCase().capitalize()
    }
}

Planet 通过构造函数定义了八颗行星及其质量和半径。surfaceGravity 使用引力常数计算重力,surfaceWeight 计算重量。toString 格式化名称(例如,“Earth”)。循环计算一个 63kg 在地球上的体重,并将其转换为在其他行星上的体重,展示了枚举作为具有实际应用的全功能对象。

集合中的枚举

枚举可以用于列表等集合中,利用其常量性质进行迭代或数据存储。

EnumInCollection.groovy
enum Fruit {
    APPLE, BANANA, ORANGE
}

def fruits = [Fruit.APPLE, Fruit.BANANA, Fruit.ORANGE]
fruits.each { println it }

Fruit 定义了三个常量。存储在列表中,fruits.each 遍历它们,打印每个名称。这说明了枚举如何与 Groovy 的集合功能集成,在保持类型安全的同时可迭代。

来源

Groovy 文档

本教程通过实际示例探讨了 Groovy 枚举。

作者

我的名字是 Jan Bodnar,我是一名充满激情的程序员,拥有丰富的编程经验。我自 2007 年以来一直撰写编程文章。迄今为止,我已撰写了超过 1400 篇文章和 8 本电子书。我在编程教学方面拥有八年以上的经验。

列出 所有 Groovy 教程