Skip to content

Commit

Permalink
feat: add guard and reorganize (#301)
Browse files Browse the repository at this point in the history
* feat: add guard and reorganize

* fix: rename if let

* add more details for guard statement

* fix example

---------

Co-authored-by: YubinChen <[email protected]>
  • Loading branch information
qazxcdswe123 and Yoorkin authored Sep 18, 2024
1 parent 1dd85d0 commit 998ff11
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 3 deletions.
54 changes: 52 additions & 2 deletions moonbit-docs/docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,12 @@ if x == y {

Curly brackets are used to group multiple expressions in the consequent or the else clause.

Note that a conditional expression always returns a value in MoonBit, and the return values of the consequent and the else clause must be of the same type.
Note that a conditional expression always returns a value in MoonBit, and the return values of the consequent and the else clause must be of the same type. Here is an example:

```moonbit
let initial = if size < 1 { 1 } else { size }
```


### While loop

Expand Down Expand Up @@ -353,7 +358,7 @@ When there is an `else` clause, the `while` loop can also return a value. The re
println(r2) //output: 7
```

## For Loop
### For Loop

MoonBit also supports C-style For loops. The keyword `for` is followed by variable initialization clauses, loop conditions, and update clauses separated by semicolons. They do not need to be enclosed in parentheses.
For example, the code below creates a new variable binding `i`, which has a scope throughout the entire loop and is immutable. This makes it easier to write clear code and reason about it:
Expand Down Expand Up @@ -476,6 +481,51 @@ fn main {
}
```

### Guard Statement

The `guard` statement is used to check a specified invariant.
If the condition of the invariant is satisfied, the program continues executing
the subsequent statements and returns. If the condition is not satisfied (i.e., false),
the code in the `else` block is executed and its evaluation result is returned (the subsequent statements are skipped).

```moonbit
guard index >= 0 && index < len else {
abort("Index out of range")
}
```

The `guard` statement also supports pattern matching: in the following example,
`getProcessedText` assumes that the input `path` points to resources that are all plain text,
and it uses the `guard` statement to ensure this invariant. Compared to using
a `match` statement, the subsequent processing of `text` can have one less level of indentation.

```moonbit
enum Resource {
Folder(Array[String])
PlainText(String)
JsonConfig(Json)
}
fn getProcessedText(resources : Map[String, Resource], path : String) -> String!Error {
guard let Some(PlainText(text)) = resources[path] else {
None => fail!("\{path} not found")
Some(Folder(_)) => fail!("\{path} is a folder")
Some(JsonConfig(_)) => fail!("\{path} is a json config")
}
...
process(text)
}
```

When the `else` part is omitted, the program terminates if the condition specified
in the `guard` statement is not true or cannot be matched.

```moonbit
guard condition // equivalent to `guard condition else { panic() }`
guard let Some(x) = expr // equivalent to `guard let Some(x) = expr else { _ => panic() }`
```


## Iterator

An iterator is an object that traverse through a sequence while providing access
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,11 @@ if x == y {
花括号用于在结果或 `else` 子句中组合表达式。

注意,在 MoonBit 中,条件表达式总是返回一个值,其结果和 `else` 子句的返回值类型必须相同。
一个配合条件表达式使用`let`绑定的例子:

```moonbit
let initial = if size < 1 { 1 } else { size }
```

### While 循环

Expand Down Expand Up @@ -351,7 +356,7 @@ fn main {
println(r2) //output: 7
```

## For 循环
### For 循环

MoonBit 也支持 C 风格的 For 循环。关键字`for`后依次跟随以分号间隔的变量初始化子句、循环条件和更新子句。三者不需要使用圆括号包裹。
例如下面的代码创建了一个新的变量绑定`i`, 它的作用域在整个循环中,且是不可变的。这更利于编写清晰的代码和推理:
Expand Down Expand Up @@ -488,6 +493,46 @@ fn main {
}
```

### 卫语句

卫语句用于检查指定的不变量。如果不变量的条件满足,程序继续执行后续的语句并返回。
如果条件不满足(即为假),则执行 `else` 块中的代码并返回它的求值结果(后续的语句会被跳过)。

```moonbit
guard index >= 0 && index < len else {
abort("Index out of range")
}
```

`guard` 语句也支持模式匹配:下面的例子中`getProcessedText`假设输入的`path`指向的都是纯文本的资源,
它使用卫语句保证这一不变量。相比于直接使用`match`语句,后续对`text`的处理过程可以少一层缩进。

```moonbit
enum Resource {
Folder(Array[String])
PlainText(String)
JsonConfig(Json)
}
fn getProcessedText(resources : Map[String, Resource], path : String) -> String!Error {
guard let Some(PlainText(text)) = resources[path] else {
None => fail!("\{path} not found")
Some(Folder(_)) => fail!("\{path} is a folder")
Some(JsonConfig(_)) => fail!("\{path} is a json config")
}
...
process(text)
}
```

当省略`else`的部分时,卫语句指定的条件不为真或者无法匹配时,程序终止。

```moonbit
guard condition // 相当于 guard condition else { panic() }
guard let Some(x) = expr // 相当于 guard let Some(x) = expr else { _ => panic() }
```


## 迭代器

迭代器(Iterator)是一个用来遍历访问某个序列的元素的对象。传统面向对象语言(例如 Java),使用 `Iterator<T>``next()`
Expand Down

0 comments on commit 998ff11

Please sign in to comment.