Skip to content

基本の型

基本の型は7つです。数値と文字列の計算結果はターゲットに依らず決まっていて、同じプログラムは JavaScript でも C でも同じ値を返します。

fn main() {
count: Int = 42
big: Int64 = 9_000_000_000
ratio: Float = 0.75
done: Bool = False
name: String = "emela"
nothing: () = ()
dbg("#{name}: #{count}, #{big}, #{ratio}, #{done}, #{nothing}")
# "emela: 42, 9000000000, 0.75, False, ()"
}
型内容
Int32ビット符号付き整数
Int6464ビット符号付き整数
Float64ビット浮動小数点数(IEEE 754 binary64)
BoolTrue か False
StringUnicode 文字の列
()Unit。値は () の1つだけ
Never値を持たない型。fail や panic の式の型

List、Option、Ordering も Prelude にある型です。Option は データ型、List は core のモジュール を見てください。

fn main() {
dbg(1_000_000) # 1000000
dbg(0xFF) # 255
dbg(0b1010) # 10
mask: Int64 = 0xFFFF_FFFF
dbg(mask) # 4294967295
later = Int64.from_int(1) + 2
dbg(later) # 3
dbg(3.14) # 3.14
dbg(1.0e9) # 1000000000.0
}

_ は桁の区切りで、値には影響しません。0x は16進、0b は2進です。

整数リテラルの型は、文脈が Int64 を求めれば Int64、それ以外は Int です。上の Int64.from_int(1) + 2 の 2 は Int64 になります。整数リテラルが Float になることはないので、Float は 1.0 と書きます。指数を付けられるのも 1.0e9 のような小数点のある形だけです。

値が文脈の型の範囲を超えるとエラーです。3000000000 は Int では書けず、Int64 の文脈なら書けます。

fn main() {
n = 3000000000
}
integer literal `3000000000` is out of range for `Int`
fn main() {
name = "emela"
count = 3
dbg("hello, #{name}!") # "hello, emela!"
dbg("#{count + 1} items") # "4 items"
dbg("list: #{[1, 2]}, #{Some(1.5)}") # "list: [1, 2], Some(1.5)"
dbg("say \"hi\"") # "say \"hi\""
dbg("literal \#{name}") # "literal \#{name}" 表示も \# の形
}

#{式} で値を埋め込めます。中には任意の式を書けて、型は Show を満たす必要があります。#{ を文字として書きたいときのエスケープは \# です。

使えるエスケープは \"、\\、\n、\t、\r、\#、\u{...}(16進のコードポイント)の7つで、それ以外の \ はエラーです。

fn main() {
s = "C:\temp\q"
}
unknown escape sequence `\q`

文字列は改行をまたげないので、複数行は """ で囲みます。

fn main() {
id = 1
query = """
SELECT *
FROM users
WHERE id = #{id}
"""
# query は "SELECT *\nFROM users\nWHERE id = 1"
}

閉じる """ の行のインデントが各行の先頭から取り除かれます。上の例では各行の先頭の空白4つが消え、最初と最後の改行も値に含めません。閉じる """ より浅くインデントした行はエラーです。

fn main() {
s = """
one
""" # one の行が閉じる """ より浅い
}

リテラルの細かい規則は 字句と予約語 にあります。

fn main() {
dbg(2147483647 + 1) # -2147483648 あふれは巻き戻る
dbg(Int.checked_add(2147483647, 1)) # None
dbg(-7 / 2) # -3 0 の方向へ切り捨て
dbg(-7 % 2) # -1 剰余の符号は被除数に従う
dbg(7 % -2) # 1
dbg(1.0 / 0.0) # Infinity
dbg(0.0 / 0.0) # NaN
dbg(-5.5 % 2.0) # -1.5
}

整数があふれると2の補数で巻き戻ります。止まらないので、あふれを検出したいときは Int.checked_add のような関数で Option を受け取ります。整数の除算は 0 の方向へ切り捨て、Float の計算は IEEE 754 のとおりです。

整数のゼロ除算だけは型に出ない異常終了(defect)になり、プログラムはそこで止まります。

fn divide(a: Int, b: Int) -> Int {
a / b
}
fn main() {
dbg(divide(10, 0))
}
defect: division by zero

失敗しうることを型で示したいときは、b == 0 を先に確かめて エラー を fail します。

算術演算子の両辺は同じ型でなければならず、Int と Float を混ぜると型エラーになります。

fn main() {
x = 1 + 1.5
}
type mismatch: expected `Int`, found `Float`

型を変えるときは関数で明示します。

fn main() {
dbg(Float.from_int(3) + 1.5) # 4.5
dbg(Int64.from_int(5)) # 5
dbg(Int64.to_int(Int64.from_int(7))) # 7
dbg(Float.floor(-1.5)) # -2
dbg(Float.ceil(1.2)) # 2
dbg(Float.round(2.5)) # 3
dbg(Float.round(-2.5)) # -3
dbg(Float.truncate(-1.5)) # -1
dbg(Int.to_string(42)) # "42"
}

Float.floor、ceil、round、truncate は Float を Int にします。結果が Int に収まらないときや NaN のときは defect です。文字列から読むときは Int.parse と Float.parse を使い、形が誤っていれば ParseError で失敗します。

ビット演算の演算子(& | << など)はなく、core の関数で書きます。

const MASK = 0b1100
fn main() {
dbg(Int.bit_and(0b1010, MASK)) # 8
dbg(0b1010 |> Int.bit_or(MASK)) # 14
dbg(Int.shift_left(1, 4)) # 16
dbg(Int.shift_left(1, 40)) # 0 幅以上のシフトは全部押し出す
dbg(Int.shift_right(-8, 1)) # -4 符号を保つ
dbg(Int.shift_right_unsigned(-1, 0)) # -1
}

Int64 にも同じ関数があります。数値の規則の全体は ターゲット にあります。

fn main() {
dbg(String.length("emela")) # 5
dbg(String.length("👍")) # 1 見た目の文字数
dbg(String.byte_size("👍")) # 4 UTF-8 のバイト数
dbg(String.append("ab", "cd")) # "abcd"
dbg(String.concat(["a", "b", "c"])) # "abc"
dbg("abc" < "abd") # True
}

String.length が返すのは見た目の文字数です。UTF-16 の長さともバイト数とも違い、バイト数は String.byte_size で取ります。s[3] のように位置を数値で指す API はないので、文字列は String.chars や String.split でたどります。

文字の型(Char)もなく、1文字は長さ1の String です。

fn main() {
dbg(String.chars("añ👍")) # ["a", "ñ", "👍"]
dbg(String.code_points("A")) # [65]
dbg(String.from_code_point(65)) # Some("A")
}

連結に + は使えません。補間か String.append、String.concat を使います。

fn main() {
s = "a" + "b"
}
expected a number (`Int`, `Int64` or `Float`), found `String`

関数の一覧は core のモジュール にあります。

True と False は Bool の構成子です。() は Unit の型であり、その唯一の値でもあって、else のない if のように値を返さない式の型になります。

Never は値を持たない型で、fail e と panic("...") の式の型です。Never はどの型とも合流するので、分岐の一方が panic でも、全体の型はもう一方の型になります。

fn first(xs: List[Int]) -> Int {
xs match {
[x, ..] -> x
[] -> panic("empty list") # Never なので Int の分岐と合流する
}
}
fn main() {
dbg(first([3, 4])) # 3
}

上ほど強く結合します。

種類演算子
後置f(x) x.name
単項!x -x
乗除* / %
加減+ -
比較== != < <= > >=
論理積&&
論理和||
パイプ|>
escape と match式 escape { ... } 式 match { ... }
fn main() {
dbg(1 + 2 * 3) # 7
dbg(-2 * 3 + 1) # -5
dbg(1 < 2 && 2 < 3) # True
dbg(!(1 == 2) || False) # True
dbg(3 |> Int.to_string) # "3"
}

比較は連鎖できないので、a < b < c は a < b && b < c と書きます。&& と || は短絡評価です。自分で定義した型に演算子を定義することはできず、Money.add(a, b) のように関数で書きます。