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!");
// 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 是布尔类型。所以,它可以是 truefalse

数字

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..5

区间是整数的序列

数组

1
2
3
4
let fruits = ["apple", "banana", "cherry"];

println(fruits);
// ["apple", "banana", "cherry"]

数组是元素的序列

记录

1
2
3
4
let p = { x: 5, y: 10 };

println(p);
// {x: 5, y: 10}

记录将字段映射到值

nil

1
2
let x = nil;
var y;
1
2
println(x); // nil
println(y); // nil

nil 表示没有值

假值

1
2
3
4
5
6
7
8
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

只有 nilfalse 是假值。

语法

注释

1
2
3
4
5
// This is a single-line comment.

// And this is
// a multi-line
// comment. ;)

Hook 只支持单行注释。抱歉!

分号

1
2
3
4
println(1) ; println(2) ; println(3) ;
println(4) ; println(5)
; println(6) ;
; // error: unexpected token `;`

需要使用分号,不允许空语句。

代码块

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 contains nil
x = 5; // now, x contains a number
x = "foo"; // a string

println(x);

数值有类型,但变量没有。

不可变变量

1
2
3
4
5
let x = 5;

x = 10; // error: cannot assign to immutable variable `x`

let y; // error: unexpected token `;`

不可变变量在声明时必须初始化。

作用域

1
2
3
4
5
6
7
8
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

当堆分配的变量超出作用域时,会自动释放。

遮蔽

1
2
3
4
5
6
let x = 5;
{
let x = 10; // shadows the outer `x`
println(x); // 10
}
println(x); // 5

变量可以被遮蔽。

运算符和表达式

算术运算

1
2
3
4
5
6
println(5 + 10); // 15
println(5 - 10); // -5
println(5 * 10); // 50
println(5 / 10); // 0.5
println(5 % 10); // 5
println(-5); // -5

基本算术运算符。

比较运算

1
2
3
4
5
6
println(5 == 10); // false
println(5 != 10); // true
println(5 < 10); // true
println(5 > 10); // false
println(5 <= 10); // true
println(5 >= 10); // false

比较运算符。

逻辑运算

1
2
3
println(true && false); // false
println(true || false); // true
println(!true); // false

逻辑运算符。

位运算和移位

1
2
3
4
5
6
println(5 & 10); // 0
println(5 | 10); // 15
println(5 ^ 10); // 15
println(~5); // -6
println(5 << 1); // 10
println(5 >> 1); // 2

位运算和移位运算符。

赋值

1
2
3
4
5
6
7
8
9
10
11
12
13
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

赋值运算符。

三元运算符

1
2
3
4
5
let x = 5;
let y = if (x > 5) 10 else 20;

println(y);
// 20

在 Hook 中,三元运算符是 if else

分支

如果

1
2
3
4
5
6
let x = 10;

if (x > 5) {
println("x is greater than 5");
}
// 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");
}
// 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");
}
// other

match 语句。

循环

while

1
2
3
4
5
6
7
var x = 0;

while (x < 5) {
print(x);
x += 1;
}
// 01234

while 循环。

do while

1
2
3
4
5
6
7
var x = 0;

do {
print(x);
x += 1;
} while (x < 5);
// 01234

do while 循环。

for

1
2
3
4
for (var i = 0; i < 5; i++) {
print(i);
}
// 01234

经典的 for 循环。

循环

1
2
3
loop {
println("Press Ctrl+C to stop");
}

无条件的 loop 循环。

中断

1
var i = 0;
1
2
3
4
5
6
7
loop {
if (i == 5) break;

print(i);
i += 1;
}
// 01234

使用 break 退出循环。

继续

1
var i = 0;
1
2
3
4
5
6
7
8
9
loop {
i += 1;
if (i % 2 == 0) continue;

print(i);

if (i == 5) break;
}
// 135

使用 continue 跳过循环体的剩余部分。

字符串

索引字符串

1
2
3
4
5
let s = "Hello";

println(s[0]); // H
println(s[1]); // e
println(s[4]); // o

对字符串进行索引返回一个包含1个字符的字符串。

切片字符串

1
2
3
4
let s = "Hello, World!";

println(s[0..5]); // Hello,
println(s[7..12]); // World!

通过传递一个区间来切片字符串。

连接字符串

1
2
3
4
let greeting = "Hi" + " there!";

println(greeting);
// Hi there!

使用 + 运算符连接字符串。

数组

索引数组

1
2
3
4
5
let a = [1, 2, 3];

println(a[0]); // 1
println(a[1]); // 2
println(a[2]); // 3

对数组进行索引返回一个元素

切片数组

1
2
3
4
5
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]

数组从零开始索引

附加元素

1
2
3
4
5
6
var a = [1, 2];

a[] = 3;

println(a);
// [1, 2, 3]

数组是可变的。使用 [] 来附加一个元素

元素赋值

1
2
3
4
5
6
var a = [1, 2, 3];

a[0] = 4;

println(a);
// [4, 2, 3]

更新数组中的元素

连接数组

1
2
3
4
5
6
let a = [1, 2];
let b = [3];
let c = a + b;

println(c);
// [1, 2, 3]

使用 + 运算符来连接数组

数组相减

1
2
3
4
5
6
let a = [1, 2, 2, 3];
let b = [2];
let c = a - b;

println(c);
// [1, 3]

获取两个数组之间的差异。

函数和闭包

函数声明

1
2
3
4
5
6
fn sum(a, b) {
return a + b;
}

println(sum(5, 10));
// 15

函数是一等公民

函数调用

1
2
3
4
5
6
fn greet(name) {
println("Hi, " + name + "!");
}

greet("John", "Doe");
// Hi, John!

参数的数量可以调整

匿名函数

1
2
3
4
5
6
let sum = |a, b| {
return a + b;
};

println(sum(5, 10));
// 15

Hook 也支持匿名函数

闭包

1
let pi = 3.14;
1
2
3
4
5
6
fn area(r) {
return pi * r * r;
}

println(area(5));
// 78.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));
// 10

函数可以作为参数传递或返回

函数的语法糖

1
2
3
4
5
6
fn factorial(n) =>
if (n == 0) 1
else n * factorial(n - 1);

println(factorial(5));
// 120

当函数体是单个表达式时使用 =>

递归

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));
// 55

支持递归

内置函数

1
2
3
4
5
6
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

参见:内置函数

结构体

结构体

1
2
3
struct Point {
x, y
}
1
2
3
4
let p = Point { 5, 10 };

println(p);
// {x: 5, y: 10}

结构体是记录的原型

访问字段

1
2
println(p.x); // 5
println(p.y); // 10

使用 . 来访问记录中的字段

字段赋值

1
2
3
4
5
p.x = 10;
p.y = 20;

println(p);
// {x: 10, y: 20}

更新记录中字段的值。

解构

解构数组

1
2
3
4
5
let a = [1, 2];
let [x, y] = a;

println(x); // 1
println(y); // 2

变量被声明并赋值

解构记录

1
2
3
4
5
let p = { x: 5, y: 10 };
let { x } = p;

println(x);
// 5

使用 {} 来解构记录

占位符

1
2
3
4
5
6
let a = [1, 2];
let [x] = a;
let [_, y] = a;

println(x); // 1
println(y); // 2

使用 _ 跳过前导或中间元素。

模块化

导入模块

1
import math;
1
2
println(math.sqrt(25));
// 5

使用 import 将一个模块引入作用域。

导出符号

1
2
3
4
5
6
// my_module.hk
fn useful_fn() {
return "Nothing";
}

return { useful: useful_fn };

返回一个包含要导出符号的记录。

导入本地模块

1
import "./my_module.hk" as my;
1
2
println(my.useful());
// Nothing

指定本地模块的路径。

选择性导入

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);
// 5

使用 {} 导入特定的符号。

核心模块

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");
// Something went wrong

使用 io 模块将内容输出到 stderr

hashing 模块

1
import hashing as h;
1
2
3
4
let d = h.sha256("Hello, world!");

println(hex(d));
// 315f5bdb76d078c43b8ac0064e4a...

hashing 模块提供哈希函数

json 模块

1
import json;
1
2
3
4
5
6
7
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。

错误处理

错误

1
2
3
4
5
println(to_int("foo"));

// runtime error: type error: argument #1 is not a convertible string
// at to_int() in <native>
// at main() in example.hk:1

Hook 使用 panic 模式进行错误处理。当出现错误时,解释器会停止运行

语法错误

1
2
3
4
println("Hello, World!");

// syntax error: unexpected end of file
// at main() in example.hk:1,25

Hook 具有严格的语法

崩溃

1
2
3
4
panic("Something went wrong");

// panic: Something went wrong
// at main() in example.hk:1

使用内置函数 panic 来引发错误

断言

1
2
3
4
assert(5 > 10, "5 is not greater than 10");

// assert: 5 is not greater than 10
// at main() in example.hk:1

使用内置函数 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);
}
// division by zero

使用一对来返回一个值和一个错误

传递错误

1
2
3
if (let [ok, err] = divide(5, 0); err) {
return [nil, err];
}

传递错误而不处理它


评论
avatar
竹山一叶
技术分享 个人心得
Follow Me
公告
欢迎光临小站,这里是我日常工作和学习中收集和整理的总结,希望能对你有所帮助:)

本站的内容经过个人加工总结而来,也参考了网友们分享的资料,如有侵权,请第一时间联系我,我将及时进行修改或删除😊
最新文章
网站资讯
文章数目 :
436
已运行时间 :
本站总字数 :
431.5k
本站访客数 :
本站总访问量 :
最后更新时间 :
文章归档文章分类文章标签复制本文标题复制本文地址
随便逛逛