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