是否可以在Groovy中为其自己的类型提供Enums实例变量?

时间:2012-07-02 22:57:36

标签: java groovy enums

我在Groovy中制作一个Text Adventure游戏作为一种练习,我遇到了一个奇怪的错误。

现在,我有一个enum表示玩家可以前往的方向,目前包含北,南,东,西,上和下。

我有一个Room课程,其中包含Map其他连通房及其路线。当我在某个Room添加Room到另一个Direction时,我希望能够将当前Room添加到另一个Room 对面方向。

例如:如果我从房间1到房间2向北添加连接,我希望能够在同一时间从房间2到房间1添加连接。

目前,我正在尝试使用enum名为Direction的附加实例变量opposite(类型为Direction)来实现此目的。这是不允许的?我没有收到编译器错误或其他任何错误,但我似乎无法让它工作。

这里是完整的enum声明:

public enum Direction {
    North(South), South(North), East(West), West(East), Up(Down), Down(Up)
    private Direction opposite
    Direction(Direction d){
        opposite = d
    }
    public opposite(){
        return opposite
    }
}

这是我从以下方式调用它的方法:

public void addConnection(Direction d, Spot spot){
    connections[d] = spot
    spot.connections[d.opposite()] = this
}

其中connectionspublic Map<Direction, Spot>

在这种情况下,条目会添加到connections,如下所示:

null:Spot@some_hexadecimal_representation

任何帮助都会很棒。谢谢!

3 个答案:

答案 0 :(得分:8)

Groovy似乎绕过Java a compilation error中的内容:

Main.java:2: illegal forward reference
    North(South), South(North), East(West), West(East), Up(Down), Down(Up);
          ^
Main.java:2: illegal forward reference
    North(South), South(North), East(West), West(East), Up(Down), Down(Up);
                                     ^
Main.java:2: illegal forward reference
    North(South), South(North), East(West), West(East), Up(Down), Down(Up);
                                                           ^
3 errors

groovy编译器没有抱怨,但是将需要前向声明的枚举值初始化为null

public enum Direction {
    North(South), South(North), East(West), West(East), Up(Down), Down(Up)
    Direction(Direction d){
        println "opposite of $this is $d"
    }
}

Direction.South // Force enum instantiation in GroovyConsole.

Outputs

opposite of North is null
opposite of South is North
opposite of East is null
opposite of West is East
opposite of Up is null
opposite of Down is Up

一个似乎在Java中运行良好的解决方案是adding a static block on the Direction class来初始化opposite值。转换为Groovy,即:

enum Direction {
    North, South, East, West, Up, Down
    private Direction opposite
    Direction getOpposite() { opposite }

    static {
        def opposites = { d1, d2 -> d1.opposite = d2; d2.opposite = d1 }
        opposites(North, South)
        opposites(East, West)
        opposites(Up, Down)
    }
}

Direction.values().each { 
    println "opposite of $it is $it.opposite"
}

现在prints the correct values

opposite of North is South
opposite of South is North
opposite of East is West
opposite of West is East
opposite of Up is Down
opposite of Down is Up

更新

Another,也许更直接,解决方案可以使用枚举上的方向索引来找到对立面:

public enum Direction {
    North(1), South(0), East(3), West(2), Up(5), Down(4)
    private oppositeIndex
    Direction getOpposite() { 
        values()[oppositeIndex]
    }
    Direction(oppositeIndex) { 
        this.oppositeIndex = oppositeIndex
    }
}

但是我发现第一个更清晰,因为它不需要索引的那些神奇数字呵呵。

更新2

现在,我可能会在这里进入高尔夫球场,但是您可以使用枚举值“ordinal()(他们的索引)来获得相反的方向without the need of an extra field

enum Direction {
    North, South, East, West, Up, Down
    Direction getOpposite() { 
        values()[ordinal() + ordinal() % 2 * -2 + 1]
    }
}

它并不像它看起来那么可怕!偶数方向(北,东,上)返回ordinal() + 1处的方向作为相反方向,而奇数方向(其他方向)返回ordinal() - 1处的方向。当然,它在很大程度上依赖于枚举中元素的顺序,但是,你不喜欢简洁吗? = d

答案 1 :(得分:2)

您可以通过将其传递给闭包并在需要相反时调用闭包来推迟对相反的评估:

public enum Direction {
    North({South}), South({North}), East({West}), West({East}), Up({Down}), Down({Up})
    private def opp
    Direction(opp) {
        this.opp = opp
    }
    public opposite() {
        return opp()
    }
}
public static void main(String[] args) {
    Direction.each { d ->
        println "${d} ... ${d.opposite()}"
    }
}

输出:

North ... South
South ... North
East ... West
West ... East
Up ... Down
Down ... Up

答案 2 :(得分:1)

当调用枚举构造函数时,看起来Directions的一半未初始化。也就是说,当您致电North(South)时,南方尚未初始化。这是下一个。

你遇到了鸡/蛋悖论,其中所有的枚举常量必须在一个之前初始化。您似乎需要重新组织一些代码来解决这个问题。我可能会建议:

public enum Direction {
    North(1), South(~1), East(2), West(~2), Up(4), Down(~4);

    private int value;

    Direction(int d){
        value = d;
    }

    private int getValue() {
        return value;
    }

    public Direction opposite(){
        for (Direction d : Direction.values()) {
            if (value == ~(d.getValue())) 
                return d;
        }
        return null;
    }
}

这利用按位运算符~来区分对立面。