Repository navigation
Enum Resolution
var m = Material.DIAMOND;
HimDSL 怎么知道 Material.DIAMOND 是"枚举值",而不是"字段 Material 的字段 DIAMOND"?
How does HimDSL know Material.DIAMOND is an enum value, not a "field DIAMOND of variable Material"?
规则是最长匹配:从代码文本里尽可能多地收集连续的 Name.Name.Name 段,然后依次尝试:
The rule is longest match: gather as many consecutive Name.Name.Name segments as possible, then try:
-
作为枚举路径(段数 ≥ 2)。
-
作为类路径(段数 ≥ 1)。
-
As an enum path (segments ≥ 2).
-
As a class path (segments ≥ 1).
成功即停,不再尝试更短的组合。
Stop on success — shorter combinations are not tried.
Material.DIAMOND
段:["Material", "DIAMOND"]
- 尝试枚举路径
Material.DIAMOND→ 找到 → 返回枚举值。
org.bukkit.Material.DIAMOND
段:["org", "bukkit", "Material", "DIAMOND"]
- 尝试
org.bukkit.Material.DIAMOND→ 找到 → 返回枚举值。 - 不会再尝试
bukkit.Material.DIAMOND或Material.DIAMOND。
Color.RED
段:["Color", "RED"]
- 尝试
Color.RED。如果Color是用户枚举,返回用户枚举值。 - 如果
Color是 Java 类,且RED是它的枚举常量,返回 Java 枚举值。 - 都没找到 → 失败。
Material.values()
段扫描会停在 .values 之前——因为 values 后面紧跟着 (,说明它是方法名,不是枚举段。
The scan stops before .values — because values is followed by (, marking it as a method, not an enum segment.
解析过程:
The resolution:
-
段 =
["Material"](只有一段)。 -
尝试枚举路径:段数不足 → 跳过。
-
尝试类路径:
Material→ 找到 → 返回类对象。 -
后续
.values()调用静态方法。 -
Segments =
["Material"](one only). -
Enum path: too few → skip.
-
Class path:
Material→ resolved → return class object. -
Subsequent
.values()calls the static method.
关键规则:后跟 ( 的段不纳入枚举路径。
Key rule: a segment followed by ( is not part of an enum path.
两种枚举共存,解析规则相同:
Both kinds coexist with the same resolution:
enum Color { RED, GREEN, BLUE };
Color.RED // 用户枚举
Material.DIAMOND // Java 枚举
两段式的优先级:先查用户枚举,再查 Java 类。
Two-segment priority: user enums are checked before Java classes.
如果用户定义了 enum Material { DIAMOND },那么 Material.DIAMOND 会解析为用户枚举而不是 Java 的 Material.DIAMOND。这是个罕见的坑——不要给用户枚举取和 Java 类相同的名字。
If a user defines enum Material { DIAMOND }, then Material.DIAMOND resolves to the user enum, not Java's. A rare trap — do not name user enums after Java classes.
如果 Material 是脚本里的一个变量,会怎样?
If Material is a script variable, what happens?
Material.DIAMOND // Material 是变量名时……
解析器先检查 Material 是否在当前作用域内已声明:
The parser first checks whether Material is a declared variable in scope:
-
是变量 → 当作
变量.字段处理,不尝试枚举。 -
不是变量 → 走枚举路径解析。
-
Is a variable → treat as
var.field, no enum resolution. -
Not a variable → proceed with enum resolution.
这就意味着:
This implies:
enum Material { DIAMOND };
var Material = someObject;
var x = Material.DIAMOND; // 用的是变量,不是枚举
变量的优先级高于枚举。给变量取和类名相同的名字能覆盖类解析,但会让代码难以理解。避免这样做。
Variables take priority over enums. Naming a variable after a class shadows the class, but hurts readability. Avoid.
enum Material { STONE, DIAMOND }; // ✗ 和 Java 的 Material 冲突
用户枚举不要用 Java 类的名字。取个独一无二的:MyMaterial、GameItem。
Material.DIAMOND.name() // ✓ 先解析枚举再调方法
Material.values // ✗ 这是个方法,不是字段,会失败
想拿到所有枚举值,写 Material.values()(带括号)。
var Diamond = Material.DIAMOND; // 变量名和枚举常量同名
// 后面用 Diamond 时,拿到的是变量,不是枚举常量
变量名不要和枚举常量名相同,会造成混淆。
Do not name user enums after Java classes.
Material.values (without parentheses) fails; Material.values() works.
Avoid naming variables after classes or enum constants.
日常脚本 99% 情况下不需要。写 Material.DIAMOND 就管用,不用想解析过程。
99% of daily scripts never need this. Material.DIAMOND just works.
遇到下列情况回来查这章:
Come back when:
-
枚举引用报"找不到"。
-
一个表达式的结果不符合直觉(拿到了变量而不是枚举)。
-
自己定义枚举和 Java 类重名。
-
An enum reference reports "not found".
-
An expression behaves unintuitively (variable instead of enum).
-
A user enum shares a name with a Java class.
-
最长匹配:尽可能收集连续
Name.Name段。 -
后跟
(的段不参与枚举匹配。 -
优先级:变量 > 用户枚举 > Java 类。
-
用户枚举不要用 Java 类名。
-
日常不需要关心;出错时回来查。
-
Longest match: collect as many
Name.Namesegments as possible. -
Segments followed by
(are excluded. -
Priority: variables > user enums > Java classes.
-
Never name user enums after Java classes.
-
Daily scripts ignore this; come back when something misfires.
下一章 [作用域与闭包 / Scopes-and-Closures] 讲变量在哪里可见,lambda 怎么捕获它们。
Next, [作用域与闭包 / Scopes-and-Closures] covers where variables are visible and how lambdas capture them.
- 首页 / Home
- 安装与快速开始 / Installation & Quick Start
- 第一个脚本 / Your First Script
- 命令速查 / Command Reference
- 自动执行脚本 / Auto-run Scripts
- 定义函数 / Defining Functions
- 函数重载 / Function Overloading
- Lambda 表达式 / Lambda Expressions
- 函数式接口 / Functional Interfaces
- 选择器总览 / Selectors Overview
- 选择器过滤器 / Selector Filters
- EntityRef 引用 / EntityRef
- 占位符参考 / Placeholders Reference
- PlaceholderAPI 桥接 / PAPI Bridge
- 创建 GUI / Creating a GUI
- GUISlot 槽位 / GUISlot
- 点击回调 / Click Callbacks
- onClose 回调 / onClose Callback
- GUI 刷新 / GUI Refresh
- 数学函数 / Math Built-ins
- 高精度计算 / BigDecimal Built-ins
- 字符串函数 / String Built-ins
- 集合函数 / Collection Built-ins
- 文件 I/O / File I/O
- 命令与 sleep / Commands & sleep