https://medium.com/@hivemind_tech/moonbit-language-in-10-features-4dc41a3a1d6c
作者:Ignacio丨德國科技公司 Hivemind 工程師
-
• 融合了Rust和Scala的優點 -
• 不使用Rust中的“借用”概念 -
• 採用垃圾回收機制 -
• 效能卓越 -
• 可編譯為WebAssembly
https://github.com/ignacio-hivemind/MoonBit-chess-example
十大特性
1、列舉型別
// This application is about a chess board,
// and how to represent it in the MoonBit language.
//
// Board is a double dimension array of BoardPlace
// cols: 0 1 2 3 4 5 6 7
// row 0: R N B Q K B N R
// row 1: P P P P P P P P
// row 2: . . . . . . . .
// row 3: . . . . . . . .
// row 4: . . . . . . . .
// row 5: . . . . . . . .
// row 6: p p p p p p p p
// row 7: r n b q k b n r
//
// The upper case letters represent the white pieces,
// whereas the lower case letters represent the black pieces.
// The pieces are: Pawn (P or p), Rook (R or r), Knight (N or n),
// Bishop (B or b), Queen (Q or q), King (K or k).
// The dots represent empty places.
/// This is documentation for the Color enum data type.
/// This is the color of the pieces in a chess game.
pubenumColor
{
White
Black
}
/// This is documentation for the Piece enum.
/// It represents the different pieces in a chess game.
pubenumPiece
{
Pawn
Rook
Knight
Bishop
Queen
King
}
2、內建Trait的自動派生
pubenumColor
{
..
}
derive
(Show,
Eq
)
pubenumPiece
{
..
}
derive
(Show,
Eq
)
pubenumColor
{
..
}
derive
(Show,
Eq
)
pubenumPiece
{
..
}
derive
(Show,
Eq
)
pubfncompare_pieces
(piece: Piece)
->
Unit {
if
piece == Pawn {
println
(
"The piece is a pawn"
)
}
else
{
println
(
"The piece is a "
+ piece.
to_string
())
}
}
3、類型別名
/// This is the representation of a place on a chess board.
/// It can be empty (None) or contain a piece with a color: Some((piece, color)).
pub typealias BoardPlace = Option[(Piece, Color)]
4、模式匹配
fndraw
(
self
: BoardPlace)
->String
{
matchself
{
None
=>
"."// empty place
Some
((piece, Color::White)) => pieceToString.get*
or_default
(piece,
"."
)
Some
((piece, Color::Black)) => pieceToString.
get_or_default
(piece,
"."
).
to_lower
()
}
}
letpieceToString
: Map[Piece,
String
] = Map::
of
([
(Piece::Pawn,
"P"
),
(Piece::Rook,
"R"
),
(Piece::Knight,
"N"
),
(Piece::Bishop,
"B"
),
(Piece::Queen,
"Q"
),
(Piece::King,
"K"
)
])
pubfnabs
(a: Int)
->
Int {
letabsolute
: Int =
if
a >=
0
{ a }
else
{ -a }
return
absolute
}
pubfnabs
(a: Int)
->
Int {
letabsolute
: Int =
if
a >=
0
{ a }
else
{ -a }
absolute
}
pubfnearly_return
(a:
String
)
->
Bool {
if
a ==
"."
{
returnfalse
}
// go on with the function logic:
// at this point you know that a is NOT “.”
// ...
}
5、結構體型別
/// This is a struct that represents a row in the board
pubstructRow
{
// Array type definition:
priv
cols: Array[BoardPlace]
// information hiding: private fields
}
derive
(Show,
Eq
)
/// This is a struct that represents the board grid
pubstructBoard
{
priv
grid: Array[Row]
}
/// This is a struct that represents the board state
pubstructBoardState
{
priv
board: Board
priv
turn: Turn
}
pubfnRow
::
empty_row
()
->
Row {
{ cols: Array::
make
(
8
,
None
) }
}
// fn <name>(self: <type>, <parameters>) -> <return type> { <body> }
// And then you can call: <object>.<name>(<parameters>)
pubfnget_turn
(
self
: BoardState)
->
Turn {
self
.turn
}
6、運算子過載
// This special method name "op_get" is used to overload the [] operator.
pubfnop_get
(
self
:Row, index: Int)
->
BoardPlace {
self
.cols[index]
}To allow
forindexed
assignment operations, you can
override
the
op_set
() method:
pubfnop_set
(
self
: Row, index: Int, value: BoardPlace)
->
Unit {
self
.cols[index] = value;
}
pubfncheck_first_element
(row: Row)
->
Unit {
letelement
: BoardPlace = row[
0
]
// Access the row with an index using “[]” operator
if
element is
Some
((Piece::Pawn, Color::White)) {
println
(
"First element is a white pawn"
)
}
...
}
7、新型別定義
/// This is a new type that represents a turn in a chess game.
pubtypeTurn Color
pubfnBoardState
::initialSetup!()
->
BoardState {
{ board: Board::initialize!(), turn:
Turn
(Color::White) }
}
8、特性
/// This trait defines a draw method that returns a string
/// representation of the object.
/// It is used to draw the different objects in the chess game to a String.
/// (although it could be in another format or different resource, like a file or
/// screen).
pub
(open)
traitDrawable
{
draw
(
Self
)
->String
}
pub
(open)
traitPaintable
{
paint
(
Self
)
->
Unit
}
// This is how you extend and combine traits in MoonBit language.
pubtraitDrawableAndPaintable : Drawable + Paintable {}
/// Implement Drawable for BoardPlace trait
pubimplDrawableforBoardPlace
with
draw
(
self
: BoardPlace)
->String
{
...
}
/// Implement Drawable for Row
implDrawableforRow
with
draw
(
self
: Row)
->String
{
...
}
9、內建測試
pubfnRow
::new_row_from_string!(rowStr:
String
)
->
Row {
assert_eq!
(rowStr.
length
(),
8
)
letcols
= []
// for loops in MoonBit
foriin0
..=
7
{
cols.
push
(
new_place_from_char
(rowStr[i]))
}
{ cols: cols }
}
test
"create a white row from string"
{
letmy_row
: Row = Row::new_row_from_string!(
"RNBQKBNR"
)
assert*eq!(my_row[
0
],
Some
((Piece::Rook, Color::White)))
assert_eq!
(my_row[
1
],
Some
((Piece::Knight, Color::White)))
assert_eq!
(my_row[
2
],
Some
((Piece::Bishop, Color::White)))
assert_eq!
(my_row[
3
],
Some
((Piece::Queen, Color::White)))
assert_eq!
(my_row[
4
],
Some
((Piece::King, Color::White)))
assert_eq!
(my_row[
5
],
Some
((Piece::Bishop, Color::White)))
assert_eq!
(my_row[
6
],
Some
((Piece::Knight, Color::White)))
assert_eq!
(my_row[
7
],
Some
((Piece::Rook, Color::White)))
}
10、函數語言程式設計支援
pubfnRow
::new_row_from_string!(rowStr:
String
)
->
Row {
assert_eq!
(rowStr.
length
(),
8
)
{ cols: rowStr.
to_array
().
map
(new_place_from_char) }
}
fncount
[A](list : @immut/list.T[A])
->
UInt {
match
list {
Nil =>
0
Cons
(*, rest) =>
count
(rest) +
1
}
}
優勢
1、垃圾回收
2、工具鏈
3、效能表現

4、與 Scala 的對比
fnmain
{
resources
.
iter
()
.map*
option
(
fn
{
(name,
Text
(
str
)) | (name,
CSV
(content=
str
)) =>
Some
((name,
str
))
(*, Executable) =>
None
})
.
map
(
fn
{
(name, content) => {
letname
= name.pad*
start
(
10
,
' '
)
letcontent
= content
.
pad_end
(
10
,
' '
)
.
replace_all
(old=
"\n"
, new=
" "
)
.
substring
(start=
0
, end=
10
)
"\{name}: \{content} ..."
}
})
.
intersperse
(
"\n"
)
.
fold
(init=
"Summary:\n"
,
String
::op_add)
|> println
}
5、社群
fnmain
{
letjson_example
: Json = {
"array"
: [
"a"
,
"b"
],
"age"
:
22
,
"name"
:
"John"
,
"boolean"
: True
}
letgreeting
=
match
json_example {
{
"age"
:
Number
(age),
"name"
:
String
(name) } =>
"Hello \{name}. You are \{age}"
* =>
"not match"
}
greeting |> println
}
最後總結
