Introduction#
A MoonBit program consists of top-level definitions including:
type definitions
function definitions
constant definitions and variable bindings
init
functions,main
function and/ortest
blocks.
Expressions and Statements#
MoonBit distinguishes between statements and expressions. In a function body, only the last clause should be an expression, which serves as a return value. For example:
fn foo() -> Int {
let x = 1
x + 1
}
fn bar() -> Int {
let x = 1
//! x + 1
x + 2
}
Expressions include:
Value literals (e.g. Boolean values, numbers, characters, strings, arrays, tuples, structs)
Arithmetical, logical, or comparison operations
Accesses to array elements (e.g.
a[0]
), struct fields (e.gr.x
), tuple components (e.g.t.0
), etc.Variables and (capitalized) enum constructors
Anonymous local function definitions
match
,if
,loop
expressions, etc.
Statements include:
Named local function definitions
Local variable bindings
Assignments
return
statementsAny expression whose return type is
Unit
, (e.g.ignore
)
A code block can contain multiple statements and one expression, and the value of the expression is the value of the code block.
Variable Binding#
A variable can be declared as mutable or immutable using let mut
or let
, respectively. A mutable variable can be reassigned to a new value, while an immutable one cannot.
A constant can only be declared at top level and cannot be changed.
let zero = 0
const ZERO = 0
fn main {
//! const ZERO = 0
let mut i = 10
i = 20
println(i + zero + ZERO)
}
Note
A top level variable binding
requires explicit type annotation (unless defined using literals such as string, byte or numbers)
can’t be mutable (use
Ref
instead)
Naming conventions#
Variables, functions should start with lowercase letters a-z
and can contain letters, numbers, underscore, and other non-ascii unicode chars.
It is recommended to name them with snake_case.
Constants, types should start with uppercase letters A-Z
and can contain letters, numbers, underscore, and other non-ascii unicode chars.
It is recommended to name them with PascalCase or SCREAMING_SNAKE_CASE.
Program entrance#
init
and main
#
There is a specialized function called init
function. The init
function is special:
It has no parameter list nor return type.
There can be multiple
init
functions in the same package.An
init
function can’t be explicitly called or referred to by other functions. Instead, allinit
functions will be implicitly called when initializing a package. Therefore,init
functions should only consist of statements.
fn init {
let x = 1
println(x)
}
There is another specialized function called main
function. The main
function is the main entrance of the program, and it will be executed after the initialization stage.
Same as the init
function, it has no parameter list nor return type.
fn main {
let x = 2
println(x)
}
The previous two code snippets will print the following at runtime:
1
2
Only packages that are main
packages can define such main
function. Check out build system tutorial for detail.
{
"is-main": true
}
test
#
There’s also a top-level structure called test
block. A test
block defines inline tests, such as:
test "test_name" {
assert_eq!(1 + 1, 2)
assert_eq!(2 + 2, 4)
inspect!([1, 2, 3], content="[1, 2, 3]")
}
The following contents will use test
block and main
function to demonstrate the execution result,
and we assume that all the test
blocks pass unless stated otherwise.