본문으로 건너뛰기
토파즈6.0 · 출시 전
다운로드 →

문서 검색

명세 6.0

방향키로 결과를 고르고 Enter를 눌러 여세요.

API 이름, 진단 번호, 규칙 또는 프로젝트 주제를 입력하세요.

    언어 · 11장 · 14개 규칙

    블록과 제어 흐름

    Blocks group execution and produce final values. Conditional branches, loops, explicit transfers, and deferred actions determine which code runs next.

    Scope and ownership

    링크

    This page owns block execution, conditional and iterative control flow, labels, explicit transfers, and deferred cleanup.

    Pattern syntax belongs to Pattern matching. Range operators belong to Expressions and operators. Function return inference belongs to Functions and generics. Collection construction and comprehensions belong to Collections and comprehensions. Concurrent timeout behavior and CLI lifecycle are outside this page.

    Control-flow syntax

    링크
    EBNF
    1. Block = "{" Statement* Expression? "}" ;
    2. IfExpression = "if" IfHead Block ("else" (IfExpression | Block))? ;
    3. IfHead = ControlOperand | "let" Pattern "=" ControlOperand ;
    4. WhileStatement = "while" WhileHead Block ;
    5. WhileHead = ControlOperand | "let" Pattern "=" ControlOperand ;
    6. ForExpression = "for" Pattern "in" ControlOperand Block ;
    7. LoopExpression = "loop" Label? Block ;
    8. BreakStatement = "break" Label? Expression? ;
    9. ContinueStatement = "continue" Label? ;
    10. ReturnStatement = "return" Expression? ;
    11. DeferStatement = "defer" Block ;
    12. ControlOperand = "(" Expression ")" ;

    This is a manually transcribed source-syntax excerpt. Statement boundaries belong to Lexical structure. Patterns belong to Pattern matching. Call arguments belong to Functions and generics.

    A label starts with an apostrophe, as in loop 'outer { ... }, break 'outer 7, or continue 'outer. The label follows loop, break, or continue.

    The iterator in for item in (expression) { ... } can be a range. In for n in (0..<6 by 2) { ... }, by 2 is part of the range expression. Range construction and bounds belong to Expressions and operators.

    Blocks and final values

    링크
    규칙topaz.rule.control-flow.block-sequence

    Block execution and final value

    On normal completion, a block executes its statements in source order. It then evaluates its optional final expression and produces that value. Trailing line breaks, blank lines, and comments preserve that final value. Without a final expression, it produces (). Write let _ = expression to evaluate an expression once without retaining its value. A final discard binding leaves the block without a tail, so the block produces (). A statement separator never consumes a value.

    이유

    A block has one final-value rule. Formatting the closing delimiter, adding blank lines, or ending a line comment cannot consume that value. A discard binding names the intention to run an expression once and finish with unit. Statement and control-flow effect contexts retain their existing result rules.

    If, else, and if let

    링크
    규칙topaz.rule.control-flow.conditional-selection

    Choosing an if branch

    An if condition has type bool. A true condition selects the then branch. A false condition selects the else arm when present and otherwise skips the then branch. An else arm can be a block or another if expression. The unselected branch is not evaluated. An if expression with an else arm produces the selected branch's value. Without an else arm, the expression always has the unit type and produces () on normal completion, including in a value position. A selected then branch runs for its effects and its value is discarded.

    이유

    Boolean conditions avoid implicit truth conversions. An if without else has the same unit result in statement and value positions.

    규칙topaz.rule.control-flow.if-let-selection

    Conditional pattern binding

    if let evaluates its scrutinee once. A successful pattern selects the then block and makes its bindings available in that branch. Failure selects the else arm when present. The result follows the if expression result rules. Without an else arm, the expression has the unit type and produces () on normal completion whether the pattern matches or fails. A selected then block discards its value when the else arm is absent.

    이유

    Evaluating the scrutinee once avoids repeating its effects. Keeping bindings in the successful branch prevents access to values from a failed match.

    While, while let, and for

    링크
    규칙topaz.rule.control-flow.while-iteration

    Testing before each while iteration

    A while loop tests its bool condition before each body execution. A true condition runs the body, and a false condition finishes the loop. A continue targeting this loop resumes at the next condition test. A break targeting it transfers control after the loop.

    이유

    Testing before the body lets an initially false condition skip the loop. Testing again after continue preserves the condition for every iteration.

    규칙topaz.rule.control-flow.while-let-iteration

    Matching before each while let iteration

    while let evaluates its scrutinee before each body execution. A successful pattern runs the body with its bindings. Pattern failure finishes the loop. A continue targeting this loop resumes at the next scrutinee evaluation.

    이유

    A fresh match checks each iteration against the current value. Its bindings describe the value that admitted that iteration.

    규칙topaz.rule.control-flow.for-iteration

    Statement and value uses of for

    A for expression evaluates its iterator expression once, visits elements in iterator order, and uses its pattern to bind each element.

    Every for runs its body for effects, discards each completed body value, and produces (). This type and its break and continue targets stay the same in a statement, parentheses, initializer, argument, or function tail. An empty iterator also produces ().

    Construct an array with [for item in (values) => expression]. Set and map comprehensions use their corresponding collection delimiters. A for expression does not collect body results. Requiring an array where a for produces () is an ordinary type mismatch.

    Iterable admission and element-pattern failure are specified below.

    이유

    A for expression performs iteration for effects, while a comprehension constructs a collection. Giving every for the same unit result prevents parentheses, binding, and argument position from changing its operation or loop targets. The existing collection delimiters make collection construction explicit. Collecting values with an early stop has a different control-flow intent. Use an accumulator and break for that case. A comprehension expresses collection that runs to completion.

    규칙topaz.rule.control-flow.for-admission

    Iterable admission and element-pattern failure

    For expressions admit Array, Set, Range and bind their element type in every context. Other resolved concrete types are rejected with TPZ5001. Iterate map keys or entries explicitly. Convert a string with scalars() or graphemes() to choose the text unit.

    A generic, foreign, or unresolved inferred type defers the element decision. At runtime the value must still be an array, set, or range. Array and set iteration traverse the collection value at entry under collection value semantics.

    A refutable element pattern must match each visited element. A miss raises a runtime type fault before the body executes for that element.

    이유

    The collection value at entry keeps an iteration stable when the source variable changes. A failed element pattern faults before the body can use missing bindings.

    Loop labels, break, continue, and return

    링크
    규칙topaz.rule.control-flow.loop-targets

    Selecting a break or continue target

    break, continue can include a target label. Lookup stays inside the current function and respects concurrent arm boundaries. An unlabeled transfer selects the innermost loop frame. A labeled transfer selects the nearest enclosing loop with that label. Targets include while loops, for expressions in every context, and loop expressions.

    A transfer without an enclosing loop is rejected during checking with TPZ5001. An unknown loop label is rejected during checking with TPZ5720.

    이유

    Function boundaries prevent loop transfers from escaping into a caller. A label makes the intended enclosing loop visible when loops are nested.

    규칙topaz.rule.control-flow.loop-value

    Leaving a loop with a value

    A loop label appears after loop. A break targeting the loop completes it with the evaluated break operand, or () when the operand is absent. A continue targeting it repeats the body. Without a contextual result type, break types must be assignable in at least one direction after widening. Disagreement is rejected during checking with TPZ5721.

    이유

    The break operand supplies the result at the exit point. Checking its type against other exits gives the loop a usable result type.

    규칙topaz.rule.control-flow.return-transfer

    Returning from a function

    A return is a statement and requires a function context. Its target cannot cross a concurrent arm boundary. Its value expression is evaluated before cleanup. A return without a value supplies (). Cleanup for crossed scopes runs before control transfers to the enclosing function's caller. A return outside a function is rejected during checking with TPZ5001.

    A return inside a lambda ends that lambda invocation. The same callable boundary determines lambda and callback propagation.

    이유

    Evaluating the return value before cleanup preserves the selected result when cleanup changes state. The enclosing function fixes the transfer destination.

    규칙topaz.rule.control-flow.non-value-loop-break

    Break values in while and for loops

    A break targeting a while loop or for expression evaluates its operand once before cleanup. The operand result is discarded. The target loop completes with (). A break without an operand follows the same cleanup and exit order. These rules also apply when the for expression is grouped or bound to a name.

    이유

    Evaluating the operand before cleanup preserves its effects. All for expressions and while loops complete with unit, so grouping or binding does not change the meaning of a break. Cleanup order remains consistent with return and value-producing break.

    Deferred cleanup

    링크
    규칙topaz.rule.control-flow.defer-shape

    Registering a deferred block

    A defer operand must be a block. A call without a block and other operands are rejected during parsing with TPZ2004. Write defer { cleanup() } to defer a call. The block is registered when execution reaches the defer statement and runs during cleanup.

    이유

    A block gives a single call and a sequence of cleanup steps the same syntax. Ordinary block rules determine how the action runs. A call form would evaluate its arguments when cleanup is registered, although cleanup happens when the scope exits. A block keeps evaluation at cleanup time. Use let to capture a value earlier when that is intended.

    규칙topaz.rule.control-flow.defer-order

    Cleanup order on normal completion and control transfer

    A reached defer belongs to its enclosing block. Cleanup runs on normal block completion and when return, break, continue, or an Err propagated by ? leaves that scope. An Ok operand of ? continues without leaving the scope or running its cleanup.

    Actions run in reverse registration order within each scope. Crossed scopes are cleaned up from innermost to outermost. The block or transfer result is evaluated before cleanup. An ordinary runtime fault follows the fault cleanup rule.

    Deadline abandonment follows abandoned arm cleanup. Remaining language cleanup is skipped and runtime handle reclamation belongs to the group.

    이유

    An Err propagated by ? leaves scopes just as an explicit return does. A common cleanup order keeps resources available until their dependents finish.

    규칙topaz.rule.control-flow.fault-skips-cleanup

    Runtime faults skip remaining cleanup

    An ordinary runtime fault is an uncatchable termination. Remaining defer blocks and using cleanup do not run. Normal completion and structured exits retain the defer order.

    Normal completion and structured exits follow the defer order.

    Deadline abandonment follows abandoned arm cleanup. Remaining language cleanup is skipped and runtime handle reclamation belongs to the group.

    이유

    A single fault outcome makes output reproducible. Skipping cleanup also prevents a second cleanup fault after termination.

    Complete examples and expected results

    링크

    Each example below is a complete file. Its expected result is specified before execution.

    A block value and a selected branch

    링크
    example.tpzA block value and a selected branch플레이그라운드 열기 →
    1. import std.io
    2. function choose() -> int {
    3. let value = {
    4. let base = 4
    5. base + 3
    6. }
    7. if (value > 5) {
    8. value * 2
    9. } else {
    10. 0
    11. }
    12. }
    13. io.writeLine("{choose()}")
    기록된 출력종료 코드 0
    14
    
    $ topaz run example.tpz --compiler self · 기록에 사용한 토파즈 5.21.3
    기대 결과

    기대 결과

    실행을 마칩니다. 종료 코드 0.

    기대 표준 출력
    1. 14
    관측한 단언 · 통과 · 5.21.3

    종료 코드 0.

    관측한 표준 출력
    1. 14

    표준 오류 출력 없음.

    • 통과 · expected 0; observed 0
    • 통과 · stdout matches the authored expectation
    • 통과 · stderr matches the authored expectation
    • 통과 · stdout matches the authored expectation

    Expected stdout is 14 followed by a newline.

    Using if let and while let

    링크
    example.tpzUsing if let and while let플레이그라운드 열기 →
    1. import std.io
    2. let mut next: Option<int> = Some(3)
    3. if let Some(value) = (next) {
    4. io.writeLine("ready: {value}")
    5. } else {
    6. io.writeLine("empty")
    7. }
    8. while let Some(value) = (next) {
    9. io.writeLine("{value}")
    10. next = None()
    11. }
    12. io.writeLine("done")
    기록된 출력종료 코드 0
    ready: 3
    3
    done
    
    $ topaz run example.tpz --compiler self · 기록에 사용한 토파즈 5.21.3
    기대 결과

    기대 결과

    실행을 마칩니다. 종료 코드 0.

    기대 표준 출력
    1. ready: 3
    2. 3
    3. done
    관측한 단언 · 통과 · 5.21.3

    종료 코드 0.

    관측한 표준 출력
    1. ready: 3
    2. 3
    3. done

    표준 오류 출력 없음.

    • 통과 · expected 0; observed 0
    • 통과 · stdout matches the authored expectation
    • 통과 · stderr matches the authored expectation
    • 통과 · stdout matches the authored expectation

    The while-let body changes the next scrutinee to None(). The following test ends the loop.

    Continue in while and break in for

    링크
    example.tpzContinue in while and break in for플레이그라운드 열기 →
    1. import std.io
    2. let mut tick = 0
    3. while (tick < 3) {
    4. tick += 1
    5. if (tick == 2) {
    6. continue
    7. }
    8. io.writeLine("{tick}")
    9. }
    10. for n in (0..<8 by 2) {
    11. if (n == 4) {
    12. break
    13. }
    14. io.writeLine("{n}")
    15. }
    16. io.writeLine("done")
    기록된 출력종료 코드 0
    1
    3
    0
    2
    done
    
    $ topaz run example.tpz --compiler self · 기록에 사용한 토파즈 5.21.3
    기대 결과

    기대 결과

    실행을 마칩니다. 종료 코드 0.

    기대 표준 출력
    1. 1
    2. 3
    3. 0
    4. 2
    5. done
    관측한 단언 · 통과 · 5.21.3

    종료 코드 0.

    관측한 표준 출력
    1. 1
    2. 3
    3. 0
    4. 2
    5. done

    표준 오류 출력 없음.

    • 통과 · expected 0; observed 0
    • 통과 · stdout matches the authored expectation
    • 통과 · stderr matches the authored expectation
    • 통과 · stdout matches the authored expectation
    • 통과 · stdout matches the authored expectation

    Both loops are used for their effects. The range syntax and step are defined under Expressions and operators.

    Breaking out of an enclosing labeled loop

    링크
    example.tpzBreaking out of an enclosing labeled loop플레이그라운드 열기 →
    1. import std.io
    2. let result: int = loop 'outer {
    3. loop {
    4. break 'outer 7
    5. }
    6. }
    7. io.writeLine("{result}")
    기록된 출력종료 코드 0
    7
    
    $ topaz run example.tpz --compiler self · 기록에 사용한 토파즈 5.21.3
    기대 결과

    기대 결과

    실행을 마칩니다. 종료 코드 0.

    기대 표준 출력
    1. 7
    관측한 단언 · 통과 · 5.21.3

    종료 코드 0.

    관측한 표준 출력
    1. 7

    표준 오류 출력 없음.

    • 통과 · expected 0; observed 0
    • 통과 · stdout matches the authored expectation
    • 통과 · stderr matches the authored expectation
    • 통과 · stdout matches the authored expectation

    The label selects the enclosing loop. The break supplies its result.

    Running deferred actions before returning

    링크
    example.tpzRunning deferred actions before returning플레이그라운드 열기 →
    1. import std.io
    2. function result() -> int {
    3. io.writeLine("value")
    4. 7
    5. }
    6. function finish() -> int {
    7. defer { io.writeLine("first") }
    8. defer {
    9. io.writeLine("second")
    10. }
    11. io.writeLine("body")
    12. return result()
    13. }
    14. io.writeLine("{finish()}")
    기대 출력종료 코드 0
    body
    value
    second
    first
    7
    
    $ topaz run example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

    실행을 마칩니다. 종료 코드 0.

    기대 표준 출력
    1. body
    2. value
    3. second
    4. first
    5. 7

    The return operand runs before cleanup. Deferred blocks run in reverse registration order.

    Cleaning up scopes during error propagation

    링크
    example.tpzCleaning up scopes during error propagation플레이그라운드 열기 →
    1. import std.io
    2. function fail() -> Result<int, string> {
    3. io.writeLine("operand")
    4. Err("stop")
    5. }
    6. function finish() -> Result<int, string> {
    7. defer { io.writeLine("outer") }
    8. let value = {
    9. defer { io.writeLine("inner-first") }
    10. defer { io.writeLine("inner-second") }
    11. fail()?
    12. }
    13. io.writeLine("unreachable")
    14. Ok(value)
    15. }
    16. io.writeLine(match (finish()) {
    17. case Ok(value) => "value={value}"
    18. case Err(error) => error
    19. })
    기대 출력종료 코드 0
    operand
    inner-second
    inner-first
    outer
    stop
    
    $ topaz run example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

    실행을 마칩니다. 종료 코드 0.

    기대 표준 출력
    1. operand
    2. inner-second
    3. inner-first
    4. outer
    5. stop

    The operand runs once before cleanup. Error propagation runs inner defers in reverse order, then the outer defer, before returning the error.

    Rejecting an invalid deferred expression

    링크
    example.tpzRejecting an invalid deferred expression플레이그라운드 열기 →
    1. defer 5
    기대 출력0이 아닌 종료 코드
    $ topaz check example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

    거절 단계 parse. 종료 코드가 0이 아닙니다.

    The integer operand is rejected at the start of 5. Replace it with a block that performs cleanup.

    Break operands run before cleanup in statement loops

    링크
    example.tpzBreak operands run before cleanup in statement loops플레이그라운드 열기 →
    1. import std.io
    2. function operand(label: string) -> int {
    3. io.writeLine(label)
    4. 7
    5. }
    6. while (true) {
    7. defer { io.writeLine("while cleanup") }
    8. break operand("while value")
    9. }
    10. for item in ([1, 2]) {
    11. defer { io.writeLine("for cleanup") }
    12. break operand("for value")
    13. }
    14. io.writeLine("done")
    기대 출력종료 코드 0
    while value
    while cleanup
    for value
    for cleanup
    done
    
    $ topaz run example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

    실행을 마칩니다. 종료 코드 0.

    기대 표준 출력
    1. while value
    2. while cleanup
    3. for value
    4. for cleanup
    5. done

    The expected result follows from current SELF source. Execution against public Topaz 5.21.3 is pending CI.

    Break in a bound for preserves its unit type

    링크
    example.tpzBreak in a bound for preserves its unit type플레이그라운드 열기 →
    1. let result: () = for item in ([1]) {
    2. break 7
    3. }
    기대 출력종료 코드 0
    표준 출력 없음.
    $ topaz check example.tpz --compiler self --format json · 대상 제품 5.21.3
    기대 결과

    기대 결과

    검사가 프로그램을 받아들입니다. 종료 코드 0.

    The explicit unit annotation also applies when the for is a binding initializer. The break operand does not become a collected element.

    Arrays, sets, ranges, and matching element patterns

    링크
    example.tpzArrays, sets, ranges, and matching element patterns플레이그라운드 열기 →
    1. import std.io
    2. for item in ([1, 2]) {
    3. io.writeLine("array {item}")
    4. }
    5. for item in (set { 3, 1, 3 }) {
    6. io.writeLine("set {item}")
    7. }
    8. for item in (2..4) {
    9. io.writeLine("range {item}")
    10. }
    11. for Some(item) in ([Some(7), Some(8)]) {
    12. io.writeLine("matched {item}")
    13. }
    기대 출력종료 코드 0
    array 1
    array 2
    set 3
    set 1
    range 2
    range 3
    range 4
    matched 7
    matched 8
    
    $ topaz run example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

    실행을 마칩니다. 종료 코드 0.

    기대 표준 출력
    1. array 1
    2. array 2
    3. set 3
    4. set 1
    5. range 2
    6. range 3
    7. range 4
    8. matched 7
    9. matched 8

    The expected result follows from current SELF source. Execution against public Topaz 5.21.3 is pending CI.

    A string must be converted to scalar elements before iteration

    링크
    example.tpzA string must be converted to scalar elements before iteration플레이그라운드 열기 →
    1. for item in ("hi") {
    2. }
    기대 출력0이 아닌 종료 코드
    $ topaz check example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

    거절 단계 check. 종료 코드가 0이 아닙니다.

    The expected result follows from current SELF source. Execution against public Topaz 5.21.3 is pending CI.

    An omitted else discards values and preserves selected effects

    링크
    example.tpzAn omitted else discards values and preserves selected effects플레이그라운드 열기 →
    1. import std.io
    2. let taken = if (true) {
    3. io.writeLine("then")
    4. 7
    5. }
    6. let skipped = if (false) {
    7. io.writeLine("unexpected")
    8. 9
    9. }
    10. io.writeLine("{taken}")
    11. io.writeLine("{skipped}")
    기대 출력종료 코드 0
    then
    ()
    ()
    
    $ topaz run example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

    실행을 마칩니다. 종료 코드 0.

    기대 표준 출력
    1. then
    2. ()
    3. ()

    An omitted else cannot produce an int result

    링크
    example.tpzAn omitted else cannot produce an int result플레이그라운드 열기 →
    1. let value: int = if (true) { 7 }
    기대 출력0이 아닌 종료 코드
    표준 출력 없음.
    $ topaz check example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

    거절 단계 check. 종료 코드가 0이 아닙니다.

    • TPZ5001 →

      if-without-else-result-type-mismatch at example.tpz:1:18

    Rejecting a deferred call without a block

    링크
    example.tpzRejecting a deferred call without a block플레이그라운드 열기 →
    1. import std.io
    2. function finish() -> () {
    3. defer io.writeLine("cleanup")
    4. }
    5. finish()
    기대 출력0이 아닌 종료 코드
    $ topaz check example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

    거절 단계 parse. 종료 코드가 0이 아닙니다.

    Wrap the cleanup call in a defer block. The current SELF parser still accepts this removed form.

    Running a deferred block at scope exit

    링크
    example.tpzRunning a deferred block at scope exit플레이그라운드 열기 →
    1. import std.io
    2. function finish() -> () {
    3. defer { io.writeLine("cleanup") }
    4. io.writeLine("body")
    5. }
    6. finish()
    기대 출력종료 코드 0
    body
    cleanup
    
    $ topaz run example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

    실행을 마칩니다. 종료 코드 0.

    기대 표준 출력
    1. body
    2. cleanup

    The body prints before the registered cleanup block runs.

    Returning through a match arm block

    링크
    example.tpzReturning through a match arm block플레이그라운드 열기 →
    1. import std.io
    2. function choose(flag: bool) -> int {
    3. while (true) {
    4. let value = match (flag) {
    5. case true => { return 7 }
    6. case false => 3
    7. }
    8. return value
    9. }
    10. 0
    11. }
    12. io.writeLine("{choose(true)}")
    13. io.writeLine("{choose(false)}")
    기대 출력종료 코드 0
    7
    3
    
    $ topaz run example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

    실행을 마칩니다. 종료 코드 0.

    기대 표준 출력
    1. 7
    2. 3

    The true arm returns from the function through the surrounding binding and loop. The false arm supplies a value to the ordinary return statement.

    For results stay unit in grouped and bound positions

    링크
    example.tpzFor results stay unit in grouped and bound positions플레이그라운드 열기 →
    1. import std.io
    2. function items(label: string) -> Array<int> {
    3. io.writeLine(label)
    4. [1, 2]
    5. }
    6. let bound = for item in (items("bound")) {
    7. io.writeLine("{item}")
    8. item * 2
    9. }
    10. let grouped = (for item in (items("grouped")) {
    11. io.writeLine("{item}")
    12. item * 3
    13. })
    14. let emptyItems: Array<int> = []
    15. let empty = for item in (emptyItems) { item }
    16. io.writeLine("{bound} {grouped} {empty}")
    기대 출력종료 코드 0
    bound
    1
    2
    grouped
    1
    2
    () () ()
    
    $ topaz run example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

    실행을 마칩니다. 종료 코드 0.

    기대 표준 출력
    1. bound
    2. 1
    3. 2
    4. grouped
    5. 1
    6. 2
    7. () () ()

    The iterator calls and body output establish evaluation order. Binding, parentheses, and an empty iterator all retain the unit result.

    Break and continue survive grouping and binding

    링크
    example.tpzBreak and continue survive grouping and binding플레이그라운드 열기 →
    1. import std.io
    2. function grouped() -> () {
    3. (for item in ([1, 2, 3, 4]) {
    4. if (item == 2) { continue }
    5. if (item == 4) { break }
    6. io.writeLine("grouped {item}")
    7. })
    8. }
    9. grouped()
    10. let result = for item in ([1, 2, 3, 4]) {
    11. if (item == 2) { continue }
    12. if (item == 4) { break }
    13. io.writeLine("bound {item}")
    14. }
    15. io.writeLine("{result}")
    기대 출력종료 코드 0
    grouped 1
    grouped 3
    bound 1
    bound 3
    ()
    
    $ topaz run example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

    실행을 마칩니다. 종료 코드 0.

    기대 표준 출력
    1. grouped 1
    2. grouped 3
    3. bound 1
    4. bound 3
    5. ()

    Both loops skip item 2 and stop before item 4. Grouping a for at a function tail and binding its result preserve the same loop targets.

    For cannot supply an array result

    링크
    example.tpzFor cannot supply an array result플레이그라운드 열기 →
    1. let values: Array<int> = for item in ([1, 2]) { item * 2 }
    기대 출력0이 아닌 종료 코드
    표준 출력 없음.
    $ topaz check example.tpz --compiler self --format json · 대상 제품 5.21.3
    기대 결과

    기대 결과

    거절 단계 check. 종료 코드가 0이 아닙니다.

    • TPZ5001 →

      for-result-type-mismatch at example.tpz:1:26

    A for expression has type (). An array annotation therefore rejects this initializer. Use an array comprehension to collect the body values.

    Collect values with an array comprehension

    링크
    example.tpzCollect values with an array comprehension플레이그라운드 열기 →
    1. import std.io
    2. let values: Array<int> = [for item in ([1, 2]) => item * 2]
    3. io.writeLine("{values[0]} {values[1]}")
    기대 출력종료 코드 0
    2 4
    
    $ topaz run example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

    실행을 마칩니다. 종료 코드 0.

    기대 표준 출력
    1. 2 4

    The collection delimiters request array construction. The body supplies one element per visited input.

    Trailing layout preserves values and discard evaluates once

    링크
    example.tpzTrailing layout preserves values and discard evaluates once플레이그라운드 열기 →
    1. import std.io
    2. function inlineTail() -> int { 7 }
    3. function linesTail() -> int {
    4. 7
    5. }
    6. function commentedTail() -> int {
    7. 7 // Trailing layout preserves this value.
    8. }
    9. function mark(value: int) -> int {
    10. io.writeLine("mark {value}")
    11. value
    12. }
    13. let discarded: () = {
    14. let _ = mark(9)
    15. }
    16. let bound: int = { 11 }
    17. io.writeLine("{inlineTail()}|{linesTail()}|{commentedTail()}|{bound}")
    18. io.writeLine("done")
    기대 출력종료 코드 0
    mark 9
    7|7|7|11
    done
    
    $ topaz run example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

    실행을 마칩니다. 종료 코드 0.

    기대 표준 출력
    1. mark 9
    2. 7|7|7|11
    3. done

    A unit context accepts successful and failed if let expressions without else

    링크
    example.tpzA unit context accepts successful and failed if let expressions without else플레이그라운드 열기 →
    1. let takenInput: int = 7
    2. let skippedInput: int = 8
    3. let taken: () = if let 7 = (takenInput) { 9 }
    4. let skipped: () = if let 7 = (skippedInput) { "discarded" }
    기대 출력종료 코드 0
    표준 출력 없음.
    $ topaz check example.tpz --compiler self --format json · 대상 제품 5.21.3
    기대 결과

    기대 결과

    검사가 프로그램을 받아들입니다. 종료 코드 0.

    An if let without else discards branch values and preserves selected effects

    링크
    example.tpzAn if let without else discards branch values and preserves selected effects플레이그라운드 열기 →
    1. import std.io
    2. let takenInput: int = 7
    3. let skippedInput: int = 8
    4. let taken = if let 7 = (takenInput) {
    5. io.writeLine("then")
    6. 9
    7. }
    8. let skipped = if let 7 = (skippedInput) {
    9. io.writeLine("unexpected")
    10. "discarded"
    11. }
    12. io.writeLine("{taken}")
    13. io.writeLine("{skipped}")
    기대 출력종료 코드 0
    then
    ()
    ()
    
    $ topaz run example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

    실행을 마칩니다. 종료 코드 0.

    기대 표준 출력
    1. then
    2. ()
    3. ()

    A runtime fault leaves defer output absent

    링크
    example.tpzA runtime fault leaves defer output absent플레이그라운드 열기 →
    1. import std.io
    2. function divide(divisor: int) -> int {
    3. defer { io.writeLine("cleanup") }
    4. io.writeLine("before fault")
    5. 12 / divisor
    6. }
    7. io.writeLine("{divide(0)}")
    기대 출력0이 아닌 종료 코드
    before fault
    
    $ topaz run example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

    거절 단계 run. 종료 코드가 0이 아닙니다.

    기대 표준 출력
    1. before fault

    The registered defer is not executed. The program prints before fault, then terminates at the division.

    Normal completion runs the registered defer

    링크
    example.tpzNormal completion runs the registered defer플레이그라운드 열기 →
    1. import std.io
    2. function divide(divisor: int) -> int {
    3. defer { io.writeLine("cleanup") }
    4. io.writeLine("before result")
    5. 12 / divisor
    6. }
    7. io.writeLine("{divide(2)}")
    기대 출력종료 코드 0
    before result
    cleanup
    6
    
    $ topaz run example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

    실행을 마칩니다. 종료 코드 0.

    기대 표준 출력
    1. before result
    2. cleanup
    3. 6

    Related rules and diagnostics

    링크

    Invalid defer body →

    Functions and generics →

    See Pattern matching for pattern forms and matching, Expressions and operators for range expressions, and Functions and generics for function declarations and return inference.

    TPZ5001 →

    Division or remainder by zero →

    메뉴

    다운로드 →