Function Overloading - HimxhMC/HimDSL GitHub Wiki
函数重载 / Function Overloading
什么是重载 / What Overloading Is
在同一个脚本里,可以有多个同名但参数不同的函数。这叫重载。例如:
A script may contain several functions with the same name but different parameters. This is overloading:
int max(int a, int b) {
if (a > b) return a;
return b;
}
double max(double a, double b) {
if (a > b) return a;
return b;
}
两个 max 名字相同,一个接收两个 int,一个接收两个 double。调用时,HimDSL 会根据参数类型和个数选择合适的那一个。
Both are named max; one takes two ints, the other two doubles. When you call it, HimDSL selects the version matching the argument types and count.
重载的判断依据 / What Distinguishes Overloads
函数能否重载,取决于参数列表,与返回类型无关。
Whether two functions overload depends on the parameter list, not the return type.
可以重载:
May overload:
int f(int x) { return x; }
int f(int x, int y) { return x + y; } // 参数个数不同
string f(string s) { return s; } // 参数类型不同
不能重载(参数列表完全相同):
Cannot overload (identical parameter lists):
int f(int x) { return x; }
double f(int x) { return x * 1.0; } // ✗ 报错:与上一个签名重复
即使返回类型不同,只要参数列表一致,就算重复定义,会报错。返回类型不参与重载判断。
Even with different return types, identical parameter lists count as duplicates and error. Return types do not distinguish overloads.
重载的解析顺序 / Resolution Order
调用重载函数时,HimDSL 按下面的顺序选择:
When calling an overloaded function, HimDSL chooses in this order:
-
参数个数。
-
参数类型。
-
有具体类型声明的优先。
-
Argument count.
-
Argument types.
-
Functions with declared types beat untyped ones.
最常见的用法是通过参数类型区分:
The most common form distinguishes by argument types:
string describe(int n) { return "整数 " + n; }
string describe(string s) { return "字符串 " + s; }
string describe(double d) { return "小数 " + d; }
int main() {
runcmd("CONSOLE", "say " + describe(42)); // 整数 42
runcmd("CONSOLE", "say " + describe("hello")); // 字符串 hello
runcmd("CONSOLE", "say " + describe(3.14)); // 小数 3.14
}
每次调用都根据实参类型选到相应的版本。
Each call selects the matching version by argument type.
参数个数优先 / Count Comes First
如果参数个数不同,HimDSL 会先按个数缩小范围,再按类型选择:
When counts differ, HimDSL narrows by count first, then by type:
int add(int a, int b) { return a + b; }
int add(int a, int b, int c) { return a + b + c; }
int main() {
add(1, 2); // 调用第一个
add(1, 2, 3); // 调用第二个
}
参数个数完全不匹配的调用不会自动补齐或截断,而是报错。
A call whose count matches no overload does not auto-pad or truncate; it errors.
类型匹配的宽松性 / Loose Type Matching
类型匹配不是严格相等,而是能否转换。例如整数可以传进期望 double 的参数:
Type matching is not strict equality but convertibility. For example, an integer may pass where a double is expected:
double half(double x) { return x / 2.0; }
int main() {
double a = half(5); // 5 被视为 5.0
double b = half(5.0);
}
反过来,double 传给 int 参数不会自动转换,需要在调用处手动 toInt:
Conversely, a double passed to an int parameter is not auto-converted; call toInt explicitly:
int negate(int x) { return -x; }
int main() {
int a = negate(5); // ✓
int b = negate(toInt(5.5)); // ✓ 显式转换
int c = negate(5.5); // ✗ 类型不匹配
}
这种"只宽不窄"的规则能帮你避免意外丢失精度。
This "widen only" rule prevents accidental precision loss.
重载与歧义 / Overloading and Ambiguity
当两个重载同样匹配一个调用时,HimDSL 会报"重载歧义"错误,而不是随便挑一个。例如:
When two overloads match a call equally well, HimDSL raises an "ambiguous overload" error instead of picking one arbitrarily:
int f(int x, int y) { return x + y; }
double f(double x, int y) { return x + y; }
int main() {
f(1, 2); // 两个都能接受,报歧义
}
修复方式是显式转换实参,让其中一个候选明确胜出:
Fix by explicitly converting the arguments so one candidate wins:
f(1.0, 2); // 明确选第二个
或者干脆不要写这种易混的重载。
Or simply avoid such easily-confused overloads.
经验法则:重载只用来区分明显不同的情况。例如参数类型不同、参数个数不同。两个重载如果只差一个类型,而调用者很难一眼看出选哪个,就应该换个名字。
Rule of thumb: overload only to distinguish clearly different cases. If two overloads differ by a single type and the caller cannot tell which will be chosen, rename one.
重载与默认参数 / Overloading and Defaults
HimDSL 没有默认参数。想要"可选参数"的效果,只能写多个重载,最短的那个调用最长的那个:
HimDSL has no default parameters. To fake optional arguments, write several overloads where the shortest delegates to the longest:
string tag(string text) {
return tag(text, "info");
}
string tag(string text, string level) {
return "[" + level + "] " + text;
}
int main() {
runcmd("CONSOLE", "say " + tag("启动完成")); // [info] 启动完成
runcmd("CONSOLE", "say " + tag("有异常", "warn")); // [warn] 有异常
}
这就是 Java 里常见的写法。每个重载做一件小事,最短的调用最长的。
This is common in Java. Each overload does one small thing; the shortest delegates to the longest.
什么时候不该重载 / When Not to Overload
重载不是越多越好。如果两个函数做的事明显不同,就不要用同名。例如:
Overloading is not about count. If two functions do clearly different things, do not share a name:
// ✗ 名同,语义不同,读起来很累
void send(string msg) { /* 发广播 */ }
void send(player p, string msg) { /* 给玩家发私信 */ }
// ✓ 换名字
void broadcast(string msg) { /* 发广播 */ }
void tell(player p, string msg) { /* 给玩家发私信 */ }
重载适合"同一个操作针对不同数据"(例如 max 对 int 和 double),而不是"完全不同的两个操作"。
Overload for "same operation on different data" (like max for int and double), not for "two different operations".
小结 / Summary
-
重载 = 同名、参数列表不同。
-
返回类型不参与判断。
-
解析顺序:个数 → 类型 → 有类型声明的优先。
-
类型匹配是"只宽不窄"。
-
歧义会报错,需要显式转换。
-
没有默认参数,用重载模拟。
-
语义不同的操作别重载。
-
Overloading = same name, different parameter lists.
-
Return type does not count.
-
Resolution: count → type → declared-type preference.
-
Type matching is "widen only".
-
Ambiguity errors; convert explicitly.
-
No default parameters; simulate with overloads.
-
Do not overload semantically different operations.
下一步 / Next Steps
下一章 [Lambda 表达式 / Lambda Expressions] 介绍一种把"代码块"当值传递的写法,GUI 回调、事件处理器都会用到。
Next, [Lambda 表达式 / Lambda Expressions] introduces passing a code block as a value — used by GUI callbacks and event handlers.