Skip to content

变量与类型

声明变量

使用 let 声明可变变量,const 声明常量:

rs
let health: int = 20;
let name: string = "Steve";
const MAX_PLAYERS: int = 16;

const 的值不能重新赋值:

rs
const PI: fixed = 3.14;
PI = 3.15; // 错误:不能重新赋值常量

const 声明支持负数字面量:

rs
const MIN_SCORE: int = -50;
const DEPTH: int = -64;      // 例如 Minecraft 基岩层高度

类型

RedScript 有一组较小的基本类型,外加几个实际写 datapack 时经常出现的 Minecraft 相关值类别:

类型描述示例
int整数(记分板,32 位有符号)42-70
fixed定点数,按 ×10000 缩放存储(v2.5.0 中 float 重命名)1.01.5
doubleIEEE 754 双精度,NBT 存储(v2.5.0 新增)x as double
string字符串"hello""Steve"
bool布尔值truefalse
selectorMinecraft 实体/玩家选择器@s@a[tag=runner]
T[]某一种元素类型的数组int[]string[]
Option<T>可能不存在的值Some(42)None

v2.5.0 说明: float 已重命名为 fixed。现有代码使用 float 会触发废弃警告,应迁移至 fixeddouble 类型为全新类型。

整数

rs
let score: int = 0;
let negative: int = -10;
score = score + 1;

定点数(fixed

fixed 会把小数作为 ×10000 缩放后的整数存入记分板。这是语言级的定点表示,用于在数据包中进行分数运算。

rs
let speed: fixed = 1.5;   // 存储为整数 15000
let half: fixed  = 0.5;   // 存储为整数 5000
let one: fixed   = 1.0;   // 存储为整数 10000

关键规则:

  • 小数字面量会按比例存储:1.0100001.5150000.00
  • fixed 运算是按比例感知的:a * ba / b 会由编译器自动补偿 ×10000
  • 原始整数字面量是 int;从 intdouble 转成 fixed 时使用 as fixed
rs
let x: int = 5;
let xf: fixed = x as fixed;  // 5 * 10000 = 50000

let d: double = 3 as double;
let df: fixed = d as fixed;   // floor(3.0 * 10000) = 30000

说明: stdlib/math.mcrs 仍然保留一些 ×1000 的历史帮助函数,如 sin_fixedcos_fixedsqrt_fixedmulfixdivfix。 这类函数用于兼容性场景,不等同于语言级 fixed 运算。

双精度(double

double 将 IEEE 754 双精度浮点数存储在 NBT 中(rs:d)。用于高精度三角函数、物理模拟或超出 int32 范围的值。

rs
let n: int    = 42;
let d: double = n as double;   // 42.0

let f: fixed  = 1.5;
let d2: double = f as double;   // 1.5(自动除以 10000)

let back: fixed = d as fixed;   // floor(d * 10000)
let back_int: int = d as int;   // floor(d)

NBT 存储: double 值存储在 rs:d __dp0(及 __dp1__dp2 等)。算术运算使用 stdlib/math_hp.mcrs 中的函数。

显式 as 转换

v2.5.0 起,数值类型转换需要显式 as 转换。intfixeddouble 之间不再支持隐式转换。

rs
// ✅ 正确 — 显式转换
let n: int   = 5;
let f: fixed = n as fixed;   // 50000

// ❌ 错误 — 隐式转换已移除
let f2: fixed = n;           // 编译错误:期望 fixed,得到 int

字符串

字符串插值使用标准 f-string(f"...{expr}..."):

rs
let player: string = "Alex";
let msg: string = f"Hello, {player}!";
say(msg); // Hello, Alex!

布尔值

rs
let alive: bool = true;
let creative: bool = false;

选择器

selector 是命令定位实体或玩家时使用的类型。它不像 int 那样存储在记分板里,而是编译成 Minecraft 选择器语法和 execute 上下文。

rs
let nearest: selector = @p;
give(nearest, "minecraft:apple", 1);

foreach (player in @a[tag=runner]) {
    actionbar(player, "Keep running!");
}

当逻辑依赖当前执行上下文时使用 @s,尤其是在 trigger / event handler 和 foreach 循环内部。

数组

数组存储多个相同类型的值:

rs
let scores: int[] = [10, 20, 30];
let names: string[] = ["Alice", "Bob"];

通过索引访问元素:

rs
let first: int = scores[0]; // 10

数组是同质的:所有元素必须是同一种类型。遍历值时用 for value in array;如果需要索引,用 for i in 0..array.len

可选值

Option<T> 表示一个值可能存在,也可能不存在。有值时用 Some(value),没有值时用 None

rs
let maybe_score: Option<int> = Some(10);
let missing_score: Option<int> = None;

if let Some(score) = maybe_score {
    say(f"Score: {score}");
}

if let Some(x) = option { ... } 是当前支持的解包方式。不要假设存在 Rust 风格的 .unwrap().unwrap_or()

类型推断

当值很明确时,RedScript 可以推断类型:

rs
let health = 20;        // 推断为 int
let name = "Steve";     // 推断为 string
let alive = true;       // 推断为 bool
let speed = 1.5;        // 推断为 fixed

const 也支持类型推断 — 类型注解是可选的:

rs
const MAX_PLAYERS = 16;     // 推断为 int
const PREFIX = "[Game]";    // 推断为 string
const RATE = 0.5;           // 推断为 fixed

显式类型声明更清晰,但不是必须的。

全局变量

在顶层声明的变量是全局的,可以从任何函数访问:

rs
let score: int = 0;

@throttle(ticks=20)
fn update() {
    score = score + 1;
    actionbar(@a, f"Score: {score}");
}

fn reset() {
    score = 0;
}

全局变量存储为 Minecraft 记分板目标。

下一步

Released under the MIT License.