.. _statements: ================= 语句 ================= .. index:: single: statements Daslang 程序是一个简单的语句序列:: stats ::= stat [';'|'\n'] stats Daslang 中的语句与 C 系列语言(C/C++、Java、C# 等)中的语句相当:有赋值、函数调用、程序流控制结构等。 还有一些自定义语句,如 blocks、structs 和 initializers(本文档稍后将详细介绍)。 语句可以用换行符分隔,或者 ';'。 ---------------- 可见性块 ---------------- .. index:: pair: block; statement :: visibility_block ::= '{' (stat)* '}' 由大括号 ({ }) 分隔的语句序列称为 visibility_block。 ----------------------- 控制流语句 ----------------------- .. index:: single: control flow statements Daslang 实现最常见的控制流语句: ``if, while, for`` ^^^^^^^^^^^^^^ true 和 false ^^^^^^^^^^^^^^ .. index:: single: true and false single: true single: false Daslang 具有强布尔类型 (bool)。只有具有布尔类型的表达式才能成为控制语句中条件的一部分。 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ if/elif/else 语句 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. index:: pair: if/else; statement pair: if; statement pair: else; statement :: stat ::= 'if' ( exp ) visibility_block (['elif' ( exp ) visibility_block])* ['else' visibility_block] 根据表达式的结果有条件地执行语句:: if ( a > b ) { a = b } elif ( a < b ) { b = a } else { print("equal") } 一行 if 语句:: if ( a > b ) a = b // 这是一个单行表示法 a = b if ( a < b ) // 这是一个后缀表示法 ^^^^^^^^^^^^^^^^^ while 语句 ^^^^^^^^^^^^^^^^^ .. index:: pair: while; statement :: stat ::= 'while' ( exp ) stat 在条件为 true 时执行语句:: while ( true ) { if ( a<0 ) { break } } ------------ 基于范围的循环 ------------ .. index:: single: Loops ^^^^^^^^ for ^^^^^^^^ .. index:: pair: for; statement :: stat ::= 'for' ( iterator 'in' [rangeexp] ) visibility_block 按顺序为 expression 中的每个元素/迭代器执行一个循环体语句:: for ( i in range(0, 10) ) { print("{i}") // 将打印 0 到 9 之间的数字 } // 或 let arr: array resize(arr, 4) for ( i in arr ) { print("{i}") // 将从第一个元素到最后一个元素打印数组的内容 } // 或 var a: array var b: int[10] resize(a, 4) for ( l, r in a, b ) { print("{l}=={r}") // 将打印数组的内容和数组 B 的前 4 个元素 } // 或 var tab: table for ( k, v in keys(tab), values(tab) ) { print("{k}:{v}") // 将打印表格的内容,格式为 key:value } 可迭代类型是通过迭代器实现的 (参阅 :ref:`Iterators `). ------- break ------- .. index:: pair: break; statement :: stat ::= 'break' break 语句终止循环的执行 (``for`` 或 ``while``). --------- continue --------- .. index:: pair: continue; statement :: stat ::= 'continue' continue 运算符跳转到循环的下一个迭代,跳过其余语句的执行。 --------- return --------- .. index:: pair: return; statement :: stat ::= return [exp] stat ::= return <- exp return 语句终止当前函数、块或 lambda 的执行,并可选择返回表达式的结果。如果省略表达式,则函数将不返回任何内容,并且假定返回类型为 void。 从同一函数返回不匹配的类型是一个错误(即,所有返回都应返回相同类型的值)。 如果函数的返回类型是显式的,则返回表达式应返回相同的类型。 例:: def foo(a: bool) { if ( a ) { return 1 } else { return 0.f // 错误, 不同的返回类型 } } def bar(a: bool): int { if ( a ) { return 1 } else { return 0.f // 错误, 不匹配的返回类型 } } def foobar(a) { return a // return type 将与 argument type 相同 } 在生成器块中,return 必须始终返回布尔表达式,其中 false 表示生成结束。 'return <- exp' 语法用于 move-on-return:: def make_array { var a: array a.resize(10) // 填充一些东西 return <- a // return 将返回 } let a <- make_array() //创建填充make_array的数组 ------ yield ------ Yield 的作用类似于生成器的 ``return``(参阅 :ref:`Generators `). 它类似于 return 语法,但只能在 ``generator`` 块中使用。 Yield 必须始终生成与生成器的值匹配的值:: var gen <- generator() <| $ { yield 0 // int 0 yield 1 // int 1 return false } ------------------ Finally 语句 ------------------ .. index:: pair: finally; statement :: stat ::= finally visibility-block Finally 声明一个区块,该区块将对任何区块(包括控制语句)执行一次。 finally 块不能包含 ``break``, ``continue``, 或 ``return`` 语句。 它旨在确保在 “all are done ” 之后执行。请考虑以下:: def test(a: array; b: int) { for ( x in a ) { if ( x == b ) { return 10 } } return -1 } finally { print("print anyway") } def test(a: array; b: int) { for ( x in a ) { if ( x == b ) { print("we found {x}") break } } finally { print("we print this anyway") } } 最后,可用于资源取消分配。 可以使用 ``defer`` 宏将代码添加到块的 finally 语句中:: require daslib/defer def foo { print("a\n") } finally { print("b\n") } def bar { defer() { print("b\n") } print("a\n") } 在上面的例子中,函数 ``foo`` 和 ``bar`` 在语义上是相同的。 多个 ``defer`` 语句以相反的顺序出现。 ``defer_delete`` 宏为其参数添加 delete 语句,并且不需要块。 --------------------------- 局部变量声明 --------------------------- .. index:: pair: Local variables declaration; statement :: initz ::= id [:type] [= exp] initz ::= id [:type] [<- exp] initz ::= id [:type] [:= exp] scope ::= `inscope` ro_stat ::= 'let' [scope] initz rw_stat ::= 'var' [scope] initz 可以在函数中的任何位置声明局部变量。它们存在于其声明和声明它们的可见性块的末尾之间。 ``let`` 声明只读变量,而 ``var`` 声明可变 (读写) 变量。 复制 ``=``、移动 ``->`` 或克隆 ``:=`` 语义指示如何初始化变量。 如果指定了 ``inscope`` , 则 ``delete id`` 语句被添加到块的 finally 部分,其中声明了变量。 它不能直接出现在 loop 块中,因为 loop 的 finally 部分只执行一次。 -------------------- 函数声明 -------------------- .. index:: pair: Function declaration; statement :: stat ::= 'def' id ['(' args ')'] [':' type ] visibility_block arg_decl = [var] id (',' id)* [':' type] args ::= (arg_decl)* 声明一个新函数。例子:: def hello { print("hello") } def hello(): bool { print("hello") return false } def printVar(i: int) { print("{i}") } def printVarRef(i: int&) { print("{i}") } def setVar(var i: int&) { i = i + 2 } ----------- try/recover ----------- .. index:: pair: try/recover; statement :: stat ::= 'try' stat 'recover' visibility-block try 语句包含一个代码块,其中可能发生 panic 情况,例如致命运行时错误或 panic 函数。try-recover 子句提供 panic 处理代码。 重要的是要理解 try/recover 不是正确的错误处理代码,也绝对不是实现 control-flow 的方法。 与 Go 语言非常相似,这实际上是一个无效的情况,通常不应该在生产环境中发生。 潜在异常的示例包括取消引用 null 指针、索引到越界数组等。 ----------- panic ----------- .. index:: pair: panic; statement :: stat ::= 'panic' '(' [string-exp] ')' 调用 ``panic`` 会导致运行时异常,并在日志中提供 string-exp。 ---------------- 全局变量 ---------------- .. index:: pair: let; statement :: stat ::= 'let|var' { shared } {private} '\n' id '=' expression stat ::= 'let|var' { shared } {private} '\n' id '<-' expression stat ::= 'let|var' { shared } {private} '\n' id ':=' expression 声明一个常量全局变量。 此变量在脚本初始化期间初始化一次(或每次手动调用脚本 init 时初始化)。 ``shared`` 表示该常量将初始化一次,并且其内存在 Daslang 上下文的多个实例之间共享。 ``private`` 表示该变量在其模块之外不可见。 -------------- enum -------------- .. index:: pair: enum; statement :: enumerations ::= ( 'id' ) '\n' stat ::= 'enum' id { enumerations } 声明一个枚举 (参阅 :ref:`Constants & Enumerations `). -------------------- 表达式语句 -------------------- .. index:: pair: Expression statement; statement :: stat ::= exp 在 Daslang 中,每个表达式也都允许是一个语句。 如果是这样,则表达式的结果将被丢弃。