Variables and Types - HimxhMC/HimDSL GitHub Wiki

变量与类型 / Variables and Types

变量是什么 / What is a Variable

变量是给一个值起的名字。声明变量后,你可以在脚本的任何地方通过这个名字读取或修改这个值。

A variable is a name for a value. After declaring it, you can read or change that value anywhere by the name.

int hp = 20;
hp = 15;                      // 修改
runcmd("CONSOLE", "say " + hp);   // 读取

本章讲解变量的声明方式、四种基本类型、通用声明 var,以及类型不匹配时的行为。

This chapter covers declarations, the four basic types, the generic var, and what happens on mismatches.


四种类型 / Four Types

HimDSL 提供了四种基本类型:

HimDSL offers four basic types:

类型 说明 示例
int 整数 int count = 3;
double 浮点数 double hp = 20.0;
bool 布尔 bool alive = true;
string 字符串 string name = "Steve";

选择哪种类型的原则:是数字就选 int 或 double,是判断结果就选 bool,是文本就选 string。整数运算(计数、索引)用 int,需要小数的场合(坐标、血量)用 double。

Rule of thumb: numbers → int or double, boolean results → bool, text → string. Use int for counting and indexing, double for values that can be fractional (coordinates, health).


声明与初始化 / Declaration and Initialization

声明变量的语法是 类型 名称 = 表达式;。分号不可省略。等号和初始值可以省略,此时变量得到该类型的默认值。

The declaration syntax is type name = expression;. The semicolon is mandatory. The = expression part is optional, and the variable then gets the type's default value.

int count;              // 默认 0
double ratio;           // 默认 0
bool ready;             // 默认 false
string label;           // 默认 null

默认值规则:

Default rules:

  • int、double → 0
  • bool → false
  • string → null

string 默认是 null,不是空字符串 ""。如果直接把它拼进字符串,会得到字面的 "null" 而不是空。声明字符串时,习惯上总是写上初值。

A string defaults to null, not the empty string "". Concatenating null into text produces the literal "null", not nothing. Get into the habit of always initializing strings.

string label = "";      // 推荐:显式空字符串

var:让编译器推断 / var: Let the Compiler Infer

var 是通用声明关键字,它的类型由右边的表达式决定。等号不可省略。

var is the generic declaration keyword; its type is decided by the right-hand expression. The = is mandatory.

var n = 5;              // n 是 int
var hp = 20.0;          // hp 是 double
var alive = true;       // alive 是 bool
var name = "Steve";     // name 是 string

什么时候用 var?两种情况下比较合适:

When to use var? Two situations fit well:

第一,右侧类型一目了然,例如 var total = players.size();,读者一看就知道是整数,写 int 反而啰嗦。

First, the right side is obvious, e.g. var total = players.size(); — readers immediately see it's an integer, and writing int is redundant.

第二,右侧类型不确定或很复杂,例如调用一个返回引用类型的函数。写 var p = players.get(i); 比写一长串类型名清晰。

Second, the right side's type is uncertain or complex, such as a function returning a reference. var p = players.get(i); reads better than a long type name.

其他情况下,显式类型更清楚,尤其是声明基本类型时。

In other cases, explicit types read better, especially for primitives.


类型检查有多严 / How Strict Is Type Checking

HimDSL 的类型检查是运行时的,而且相当宽松。下面这种写法不会在编译期报错:

Type checking in HimDSL is runtime and fairly lenient. The following does not error at compile time:

int x = "hello";        // 编译通过

真正报错是在使用 x 的时候。例如:

The actual error surfaces when you use x. For example:

int x = "hello";
int y = x + 1;          // 运行时报错:字符串不能参与算术

这种设计有两面性。好的一面是脚本写起来更灵活,不必事事声明精确类型。坏的一面是错误可能很晚才暴露——你需要在实际执行到那一行时才看到问题。

This design cuts both ways. Good: scripts are more flexible, and you don't have to nail every type. Bad: errors surface late — only when execution reaches that line.

实用建议:声明时尽量写清楚的类型。即使 var 写起来方便,基本类型还是写 int、double、bool、string 更安全。

Practical advice: write explicit types whenever you can. Even though var is convenient, primitives are safer as int, double, bool, string.


类型转换 / Type Conversion

不同类型之间不能直接赋值使用,需要转换。内置函数提供了常用的转换:

Different types cannot be used interchangeably; convert first. Built-ins cover the common cases:

int n = toInt("42");         // 字符串 "42" → 42
double d = toDouble("3.14"); // 字符串 "3.14" → 3.14
string s = toString(42);     // 42 → "42"
bool b = toBool("true");     // "true" → true
long l = toLong("9999");     // 字符串 → long

toInt、toDouble、toBool 在转换失败时不会抛异常,而是返回默认值(0、0.0、false)。所以转换前可以先检查,也可以容忍失败。

toInt, toDouble, and toBool do not throw on failure — they return defaults (0, 0.0, false). You can either validate first or accept the default.

从命令传入的参数永远是字符串,需要数字时必须先转换:

Arguments from the command line are always strings; convert before using as numbers:

int main(string countText) {
    int count = toInt(countText);
    runcmd("CONSOLE", "say 循环 " + count + " 次");
}

整数与浮点的运算 / Integer and Floating Arithmetic

两个 int 相加的结果是 int;只要有一个是 double,结果就是 double:

Two ints add to an int; if any operand is double, the result is double:

int a = 5 / 2;           // 2  (整数除法)
double b = 5 / 2.0;      // 2.5
double c = 5.0 / 2;      // 2.5

整数除法会向零截断,不是四舍五入。5 / 2 得到 2,不是 2.5,也不是 3。这是新手常踩的坑:算比例的时候要写 5.0 / 2。

Integer division truncates toward zero, not rounds. 5 / 2 gives 2, not 2.5 or 3. A common pitfall: for ratios write 5.0 / 2.


变量的作用域 / Scope

变量在声明它的花括号块内可见,出了块就消失:

Variables are visible within the braces where they were declared; outside they disappear:

int main() {
    int outer = 1;

    if (true) {
        int inner = 2;
        outer = outer + inner;    // ✓ outer 可见
    }

    inner = 5;                    // ✗ inner 已不存在
}

函数内的变量与函数外互不干扰。这一点在写 for 循环时要注意:循环变量 i 在循环外不可见。

Variables inside a function are separate from outside. This matters for for loops: the loop variable i is not visible outside the loop.


小结 / Summary

  • 四种基本类型:int、double、bool、string。

  • var 自动推断,等号不可省。

  • 类型检查发生在运行时,宽松但错误暴露晚。

  • 内置的 toInt / toDouble / toString / toBool 用于转换。

  • 整数除法截断,算比例要写 x.0。

  • 变量作用域限于声明的花括号内。

  • Four primitives: int, double, bool, string.

  • var infers type; the = is required.

  • Type checks are runtime, lenient, but errors surface late.

  • toInt / toDouble / toString / toBool convert.

  • Integer division truncates; write x.0 for ratios.

  • Variables live within the braces where they are declared.


下一步 / Next Steps

下一章 [运算符 / Operators] 系统讲解算术、比较、逻辑、自增自减、复合赋值。之前示例里出现的 +、<、&&、++ 都会在那里完整展开。

Next, [运算符 / Operators] covers arithmetic, comparison, logical, increment/decrement, and compound assignment. The +, <, &&, ++ you have seen will be fully explained there.