Hook 备忘清单 === Hook 备忘单是 [Hook](https://github.com/hook-lang/hook/) 编程语言的一页参考表。 ## 入门 ### 介绍 - [GitHub](https://github.com/hook-lang/hook) - [在线运行](https://hook-lang.github.io/hook-playground) - [示例](https://github.com/hook-lang/hook/tree/main/examples) - [VSCode 扩展](https://marketplace.visualstudio.com/items?itemName=fabiosvm.hook) ### Hook 看起来是什么样的? ```rust fn factorial(n) { if (n == 0) return 1; return n * factorial(n - 1); } ``` Hook 具有类似于 `C` 的现代语法。 ### Hello, World ```js println("Hello, World!"); // Hello, World! ``` Hook 中的 `Hello, World!` 程序。 ### 使用 Homebrew 安装 ```text brew tap hook-lang/hook brew install hook hook --help ``` 解释器可以通过 [`Homebrew`](https://brew.sh) 获取。 ### 在 Windows 上安装 ```bash cd %tmp% curl -sSLO https://raw.githubusercontent.com/hook-lang/hook/main/scripts/install.bat install ``` 这是你在 `Windows` 上安装的方法。 ## 类型和值 ### 基本类型 | | | | -------- | :-------- | | `Nil` | `Bool` | | `Number` | `String` | | `Range` | `Array` | | `Record` | `Closure` | 基本类型列表。 ### 布尔值 ```js let x = true; let y = false; ``` Bool 是布尔类型。所以,它可以是 `true` 或 `false` ### 数字 ```js let x = 0; let degree = 45; // 整数 let pi = 3.14; // 浮点数 ``` 数字可以是整数或浮点数 ### 字符串 ```js let empty = ""; let name = "John"; let message = 'Hello, "John"!'; ``` 字符串可以用单引号或双引号表示 ### 区间 ```js let range = 1..5; println(range); // 1..5 ``` 区间是整数的序列 ### 数组 ```js let fruits = ["apple", "banana", "cherry"]; println(fruits); // ["apple", "banana", "cherry"] ``` 数组是元素的序列 ### 记录 ```js let p = { x: 5, y: 10 }; println(p); // {x: 5, y: 10} ``` 记录将字段映射到值 ### **nil** 值 ```swift let x = nil; var y; ``` ```js println(x); // nil println(y); // nil ``` `nil` 表示没有值 ### 假值 ```swift if (nil) "true" else "false"; // false if (false) "true" else "false"; // false if (true) "true" else "false"; // true if (0) "true" else "false"; // true if (1) "true" else "false"; // true if ("") "true" else "false"; // true if ([]) "true" else "false"; // true if ({}) "true" else "false"; // true ``` 只有 `nil` 和 `false` 是假值。 ## 语法 ### 注释 ```js // This is a single-line comment. // And this is // a multi-line // comment. ;) ``` Hook 只支持单行注释。抱歉! ### 分号 ```js println(1) ; println(2) ; println(3) ; println(4) ; println(5) ; println(6) ; ; // error: unexpected token `;` ``` 需要使用分号,不允许空语句。 ### 代码块 ```js { println("Hello"); { println("World"); } } ``` 使用代码块定义作用域。 ### 保留字 | | | | | | ------- | :------- | :--------- | :------ | | `as` | `break` | `continue` | `do` | | `else` | `false` | `fn` | `for` | | `from` | `if` | `import` | `in` | | `inout` | `let` | `loop` | `match` | | `nil` | `return` | `struct` | `trait` | | `true` | `var` | `while` | | 有少量保留字。 ### 标识符 ```php var lowercase; var CAPS_LOCK; var camelCase; var PascalCase; var snake_case; var _123; ``` 标识符是区分大小写的。 ## 变量 ### 变量 ```js var x; // x contains nil x = 5; // now, x contains a number x = "foo"; // a string println(x); ``` 数值有类型,但变量没有。 ### 不可变变量 ```js let x = 5; x = 10; // error: cannot assign to immutable variable `x` let y; // error: unexpected token `;` ``` 不可变变量在声明时必须初始化。 ### 作用域 ```js let x = 5; { let y = 15; println(x); // 10 println(y); // 15 } println(x); // 5 println(y); // error: variable `y` is used but not defined ``` 当堆分配的变量超出作用域时,会自动释放。 ### 遮蔽 ```js let x = 5; { let x = 10; // shadows the outer `x` println(x); // 10 } println(x); // 5 ``` 变量可以被遮蔽。 ## 运算符和表达式 ### 算术运算 ```js println(5 + 10); // 15 println(5 - 10); // -5 println(5 * 10); // 50 println(5 / 10); // 0.5 println(5 % 10); // 5 println(-5); // -5 ``` 基本算术运算符。 ### 比较运算 ```js println(5 == 10); // false println(5 != 10); // true println(5 < 10); // true println(5 > 10); // false println(5 <= 10); // true println(5 >= 10); // false ``` 比较运算符。 ### 逻辑运算 ```js println(true && false); // false println(true || false); // true println(!true); // false ``` 逻辑运算符。 ### 位运算和移位 ```js println(5 & 10); // 0 println(5 | 10); // 15 println(5 ^ 10); // 15 println(~5); // -6 println(5 << 1); // 10 println(5 >> 1); // 2 ``` 位运算和移位运算符。 ### 赋值 ```js var x = 5; // 5 x += 10; // 15 x -= 10; // 5 x *= 10; // 50 x /= 10; // 5 x %= 10; // 5 x &= 10; // 0 x |= 10; // 10 x ^= 5; // 15 x <<= 5; // 480 x >>= 5; // 15 x++; // 16 x--; // 15 ``` 赋值运算符。 ### 三元运算符 ```js let x = 5; let y = if (x > 5) 10 else 20; println(y); // 20 ``` 在 Hook 中,三元运算符是 `if else`。 ## 分支 ### 如果 ```js let x = 10; if (x > 5) { println("x is greater than 5"); } // x is greater than 5 ``` `if` 语句。 ### 如果否则 ```js let x = 11; if (x == 5) { println("x is 5"); } else if (x == 10) { println("x is 10"); } else { println("x is neither 5 nor 10"); } // x is neither 5 nor 10 ``` `if else` 语句。 ### 匹配 ```rust let x = 5; match (x) { 1 => println("one"); 2 => println("two"); 3 => println("three"); _ => println("other"); } // other ``` `match` 语句。 ## 循环 ### while ```js var x = 0; while (x < 5) { print(x); x += 1; } // 01234 ``` `while` 循环。 ### do while ```js var x = 0; do { print(x); x += 1; } while (x < 5); // 01234 ``` `do while` 循环。 ### for ```rust for (var i = 0; i < 5; i++) { print(i); } // 01234 ``` 经典的 `for` 循环。 ### 循环 ```rust loop { println("Press Ctrl+C to stop"); } ``` 无条件的 `loop` 循环。 ### 中断 ```js var i = 0; ``` ```rust loop { if (i == 5) break; print(i); i += 1; } // 01234 ``` 使用 `break` 退出循环。 ### 继续 ```js var i = 0; ``` ```rust loop { i += 1; if (i % 2 == 0) continue; print(i); if (i == 5) break; } // 135 ``` 使用 `continue` 跳过循环体的剩余部分。 ## 字符串 ### 索引字符串 ```js let s = "Hello"; println(s[0]); // H println(s[1]); // e println(s[4]); // o ``` 对字符串进行索引返回一个包含1个字符的字符串。 ### 切片字符串 ```js let s = "Hello, World!"; println(s[0..5]); // Hello, println(s[7..12]); // World! ``` 通过传递一个区间来切片字符串。 ### 连接字符串 ```js let greeting = "Hi" + " there!"; println(greeting); // Hi there! ``` 使用 `+` 运算符连接字符串。 ## 数组 ### 索引数组 ```js let a = [1, 2, 3]; println(a[0]); // 1 println(a[1]); // 2 println(a[2]); // 3 ``` 对数组进行索引返回一个元素 ### 切片数组 ```js let a = [1, 2, 3, 4]; println(a[0..2]); // [1, 2, 3] println(a[1..3]); // [2, 3, 4] println(a[2 .. len(a) - 1]); // [3, 4] ``` 数组从零开始索引 ### 附加元素 ```js var a = [1, 2]; a[] = 3; println(a); // [1, 2, 3] ``` 数组是可变的。使用 `[]` 来附加一个元素 ### 元素赋值 ```js var a = [1, 2, 3]; a[0] = 4; println(a); // [4, 2, 3] ``` 更新数组中的元素 ### 连接数组 ```js let a = [1, 2]; let b = [3]; let c = a + b; println(c); // [1, 2, 3] ``` 使用 `+` 运算符来连接数组 ### 数组相减 ```js let a = [1, 2, 2, 3]; let b = [2]; let c = a - b; println(c); // [1, 3] ``` 获取两个数组之间的差异。 ## 函数和闭包 ### 函数声明 ```rust fn sum(a, b) { return a + b; } println(sum(5, 10)); // 15 ``` 函数是一等公民 ### 函数调用 ```rust fn greet(name) { println("Hi, " + name + "!"); } greet("John", "Doe"); // Hi, John! ``` 参数的数量可以调整 ### 匿名函数 ```js let sum = |a, b| { return a + b; }; println(sum(5, 10)); // 15 ``` Hook 也支持匿名函数 ### 闭包 ```js let pi = 3.14; ``` ```rust fn area(r) { return pi * r * r; } println(area(5)); // 78.5 ``` Hook 中的闭包只捕获数值 ### 高阶函数 ```rust fn apply(f, x) { return f(x); } fn double(x) { return x * 2; } println(apply(double, 5)); // 10 ``` 函数可以作为参数传递或返回 ### 函数的语法糖 ```rust fn factorial(n) => if (n == 0) 1 else n * factorial(n - 1); println(factorial(5)); // 120 ``` 当函数体是单个表达式时使用 `=>` ### 递归 ```rust fn fib(n) { if (n < 2) return n; return fib(n - 1) + fib(n - 2); } println(fib(10)); // 55 ``` 支持递归 ### 内置函数 ```js println(type(5)); // number println("1" + to_string(2)); // 12 println(len("foo")); // 3 ``` 有许多内置函数 ### 更多内置函数 | | | | | ----------- | :-------- | :---------- | | `print` | `println` | `type` | | `is_nil` | `is_bool` | `to_number` | | `to_string` | `hex` | `len` | | `exit` | `assert` | `panic` | 参见:[内置函数](https://github.com/hook-lang/hook/blob/main/docs/built-in.md) ## 结构体 ### 结构体 ```rust struct Point { x, y } ``` ```js let p = Point { 5, 10 }; println(p); // {x: 5, y: 10} ``` 结构体是记录的原型 ### 访问字段 ```js println(p.x); // 5 println(p.y); // 10 ``` 使用 `.` 来访问记录中的字段 ### 字段赋值 ```js p.x = 10; p.y = 20; println(p); // {x: 10, y: 20} ``` 更新记录中字段的值。 ## 解构 ### 解构数组 ```js let a = [1, 2]; let [x, y] = a; println(x); // 1 println(y); // 2 ``` 变量被声明并赋值 ### 解构记录 ```js let p = { x: 5, y: 10 }; let { x } = p; println(x); // 5 ``` 使用 `{}` 来解构记录 ### 占位符 ```js let a = [1, 2]; let [x] = a; let [_, y] = a; println(x); // 1 println(y); // 2 ``` 使用 `_` 跳过前导或中间元素。 ## 模块化 ### 导入模块 ```js import math; ``` ```js println(math.sqrt(25)); // 5 ``` 使用 `import` 将一个模块引入作用域。 ### 导出符号 ```rust // my_module.hk fn useful_fn() { return "Nothing"; } return { useful: useful_fn }; ``` 返回一个包含要导出符号的记录。 ### 导入本地模块 ```python import "./my_module.hk" as my; ``` ```js println(my.useful()); // Nothing ``` 指定本地模块的路径。 ### 选择性导入 ```js import { pow, sqrt } from math; let [ b, c ] = [ 4, 3 ]; let a = sqrt(pow(b, 2) + pow(c, 2)); println(a); // 5 ``` 使用 `{}` 导入特定的符号。 ### 核心模块 | | | | | | ---------- | :------- | :----- | :-------- | | `math` | `os` | `io` | `numbers` | | `strings` | `arrays` | `utf8` | `hashing` | | `encoding` | `socket` | `json` | `lists` | 参见:[核心模块](https://github.com/hook-lang/hook/blob/main/docs/core-modules.md) ### 扩展模块 | | | | | | --------- | :-------- | :------ | :-------- | | `bigint` | `crypto` | `curl` | `fastcgi` | | `geohash` | `leveldb` | `mysql` | `redis` | | `regex` | `sqlite` | `uuid` | `zeromq` | 这是扩展模块的列表。 ### **io** 模块 ```js import { stderr, writeln } from io; writeln(stderr, "Something went wrong"); // Something went wrong ``` 使用 `io` 模块将内容输出到 `stderr` ### **hashing** 模块 ```python import hashing as h; ``` ```js let d = h.sha256("Hello, world!"); println(hex(d)); // 315f5bdb76d078c43b8ac0064e4a... ``` `hashing` 模块提供哈希函数 ### **json** 模块 ```js import json; ``` ```js let j = '{"x": 1, "y": 2}'; let p = json.decode(j); println(p.x); // 1 let k = json.encode(p); println(type(k)); // string ``` 使用 `json` 模块处理 JSON。 ## 错误处理 ### 错误 ```js println(to_int("foo")); // runtime error: type error: argument #1 is not a convertible string // at to_int() in // at main() in example.hk:1 ``` Hook 使用 panic 模式进行错误处理。当出现错误时,解释器会停止运行 ### 语法错误 ```js println("Hello, World!"); // syntax error: unexpected end of file // at main() in example.hk:1,25 ``` Hook 具有严格的语法 ### 崩溃 ```js panic("Something went wrong"); // panic: Something went wrong // at main() in example.hk:1 ``` 使用内置函数 `panic` 来引发错误 ### 断言 ```js assert(5 > 10, "5 is not greater than 10"); // assert: 5 is not greater than 10 // at main() in example.hk:1 ``` 使用内置函数 `assert` 来检查条件 ### 返回错误 ```rust fn divide(a, b) { if (b == 0) return [nil, "division by zero"]; return a / b; } if (let [ok, err] = divide(5, 0); ok) { println(ok); } else { println(err); } // division by zero ``` 使用一对来返回一个值和一个错误 ### 传递错误 ```rust if (let [ok, err] = divide(5, 0); err) { return [nil, err]; } ``` 传递错误而不处理它