Sisu

Reference / Literals

Literals

A literal is a value that the source writes directly: a number, a character, a string or a boolean.

fn main() {
    print(42)          // 42
    print(2.5)         // 2.5
    print('ä')         // ä
    print("sauna")     // sauna
    print(true)        // true
}
Literal Examples Type
Integer 42, 1_000_000, 0xff, 0b1010, 0o17 i64, or u8 or f64 when the context expects one
Float 2.5, 1e-3, 6.674e-11 f64
Character 'a', 'ä', '\n', '\u{1F600}' char
String "sauna", "n = {n}" string
Boolean true, false bool

Integer literals

An integer literal is a sequence of decimal digits, such as 42. Zeros at the start do not change the base: 007 is 7.

fn main() {
    print(1_000_000 + 1)    // 1000001
    print(007)              // 7
}

A - before a literal is the unary minus operator. It is not part of the literal.

Bases

A prefix gives a different base: 0x for hexadecimal, 0b for binary and 0o for octal. A hexadecimal digit can be upper case or lower case, but the prefix must be lower case.

fn main() {
    print(0xff)        // 255
    print(0xFF)        // 255
    print(0b1010)      // 10
    print(0o17)        // 15
}

These are errors:

  • An upper case prefix, such as 0XFF (E0075).
  • A prefix with no digits after it, such as 0x (E0076).
  • A digit that is not of the base, such as the 2 in 0b102 (E0077).
fn main() {
    print(0b102)       // error[E0077]
}

E0077: what this error means

A literal with a prefix is an integer. It has no fraction and no exponent.

Digit separators

A _ between two digits makes a long number easier to read. It does not change the value.

fn main() {
    print(1_000)           // 1000
    print(0xff_ff)         // 65535
    print(0b1111_0000)     // 240
}

A _ must have a digit on each side. So 1__000, 1000_ and 0x_ff are errors (E0008). _1000 is not a literal: it is a name.

fn main() {
    print(1000_)       // error[E0008]
}

E0008: what this error means

Range

The value of an integer literal must fit in an i64. The largest literal is 9223372036854775807. A larger one is an error (E0009).

fn main() {
    print(9223372036854775808)    // error[E0009]
}

E0009: what this error means

The one exception is the smallest i64. Its magnitude, 9223372036854775808, is a literal only directly after a unary -. Spaces, tabs, line breaks and comments can come between the - and the digits. No other token can come between them, so parentheses cannot.

fn main() {
    print(-9223372036854775808)    // -9223372036854775808
}
fn main() {
    print(-(9223372036854775808))  // error[E0009]
}

E0009: what this error means

The same rule applies in other bases, such as -0x8000000000000000.

A ., ?. or [ after the literal applies before the - does (Precedence). So -9223372036854775808.max(0) is an error.

The type of an integer literal

An integer literal is an i64, unless its context makes it a u8 or an f64.

fn main() {
    let b: u8 = 250
    let x = 2.5
    print(b + 5)       // 255
    print(x * 2)       // 5.0
    print(7 / 2)       // 3
}

The rules, in order:

  • When the context expects a u8 or a u8?, the literal is a u8. When the context expects an f64 or an f64?, the literal is an f64.
  • In a group of operands, the operands that are not integer literals decide the type of its integer literals. If one of them is a u8 or a u8?, the literals in the group are u8s. If one is an f64, an f64? or a float literal, they are f64s. These are the groups:
  • When a literal has no expected type and is not in a group, it is an i64.

These places give an expected type:

  • the declared type of a let or a const
  • the place of an assignment, also with += and the other compound operators
  • a parameter of a function or a method, also a built-in method such as max
  • a field of a class constructor, or a value of an enum variant
  • the return type, for a return value and for the last expression of a function body
  • the element type, for each element of an array literal
  • the type of the value in the left operand of ??, for the right operand
  • the expected type of an arithmetic operation or a unary -, for its operands
  • the type of the value that a match tests, for a literal in a pattern
  • the expected type of a loop, for each break value
  • the expected type of a block, for its last expression
  • the expected type of an if or a match, for each branch or arm
fn main() {
    let o: f64? = None
    let c = 2
    let x = 2.5
    print(o ?? 3)                        // 3.0
    print(match c { 1 => x; _ => 4 })    // 4.0
    print(x.max(7))                      // 7.0
    let y: f64 = loop { break 1 }
    print(y)                             // 1.0
    let z: f64 = -3 + 1
    print(z)                             // -2.0
}

When a loop has no expected type, its break values give the loop its type. Their types must agree (E0032).

An operand that has only integer literals, +, -, *, /, %, unary - and parentheses counts as a literal in a group. So (2 + 3) * b is a u8 product when b is a u8.

fn main() {
    let b: u8 = 50
    print((2 + 3) * b)    // 250
}

A u8 literal must be 255 or less (E0040). An integer literal that becomes an f64 must have a value that an f64 holds exactly (E0104). Every integer up to 2^53 is such a value.

fn main() {
    let b: u8 = 256    // error[E0040]
    let c: u8 = 1
    print(c < 300)     // error[E0040]
}

E0040: what this error means

E0040: what this error means

A float literal never becomes an integer.

Float literals

A float literal has a fraction, an exponent or both. Its type is always f64.

fn main() {
    print(2.5)          // 2.5
    print(3.0e8)        // 300000000.0
    print(1e-3)         // 0.001
    print(1_000.000_1)  // 1000.0001
}

The rules:

  • A fraction is a . with at least one digit on each side. So 1. and .5 are errors (E0101).
  • An exponent is e or E, an optional + or -, and at least one digit (E0102).
  • A digit separator can go between two digits of the integer part, the fraction or the exponent.
  • The value is the f64 nearest to the literal. A literal so large that it rounds to infinity is an error (E0103). A literal too small for an f64, such as 1e-400, becomes 0.0.
fn main() {
    print(1.)          // error[E0101]
}

E0101: what this error means

A . after an integer starts a fraction only when a digit follows it. So 0..n is a range, 1.max(2) calls a method on 1, and 1.e5 is the integer 1, a . and the name e5.

fn main() {
    print(1.max(2))    // 2
}

Character literals

A character literal is one Unicode scalar value between single quotes, such as 'a' or 'ä'. Its type is char. An escape can write the value.

fn main() {
    print('a')         // a
    print('\u{E4}')    // ä
    print('{')         // {
}

A character literal holds exactly one code point. So '' and 'ab' are errors (E0092). An e followed by a combining accent is two code points, so it is an error too.

fn main() {
    print('ab')        // error[E0092]
}

E0092: what this error means

A ' in a character literal must be the escape \'. A " can stand as it is. A character literal must close on its line (E0093).

String literals

A string literal is text between double quotes, such as "sauna". Its type is string. Strings and formatting tells how a string works. The text can hold any character, and the escapes below.

fn main() {
    print("sauna")           // sauna
    print("it's \"hot\"")    // it's "hot"
}

A string literal must close on its line (E0093). For a line break in the text, write \n.

Interpolation

A { in a string literal starts an interpolation. The program calculates the expression between { and }, and puts its text into the string.

fn main() {
    let n = 3
    print("{n} + {n} = {n + n}")    // 3 + 3 = 6
}

The rules:

  • The value of the expression must be an i64, a u8, an f64, a bool, a char or a string (E0098). The section Text of other types is in development, and it changes this rule.
  • The expression can include a string literal of its own: "{ "a" + "b" }".
  • The expression must be on the line of the string literal.
  • A } closes the interpolation only when every bracket opened in the interpolation is closed. A { or } in a string or character literal in the expression does not count, so "{ c == '}' }" is valid.
  • A : after the expression starts a format spec, such as "{x:.2}" (Format specs).
  • An empty interpolation, "{}" or "{ }", is an error (E0096).
  • A comment cannot be in an interpolation (E0097).
  • A } in the text, outside an interpolation, is an error (E0095).
fn main() {
    let xs = [1, 2]
    print("xs = {xs}")       // error[E0098]
}

E0098: what this error means

For a literal brace in the text, write \{ or \}.

fn main() {
    print("\{n\}")     // {n}
}

Escapes

Character and string literals take the same escapes.

Escape Value
\n line feed
\t tab
\r carriage return
\0 null, the code point 0
\\ \
\" "
\' '
\{ {, not an interpolation
\} }
\u{...} the Unicode scalar value with that hexadecimal code, such as \u{E4} for ä
fn main() {
    print("a\tb")              // a	b
    print("C:\\temp")          // C:\temp
    print("\u{1F600}")         // 😀
}

The rules:

  • Any other character after a \ is an error (E0089). There is no \x byte escape.
  • A \u escape has 1 to 6 hexadecimal digits between { and } (E0090).
  • Its value must be a Unicode scalar value: 0 to 10FFFF, but not D800 to DFFF (E0091).
fn main() {
    print("\q")        // error[E0089]
}

E0089: what this error means

Boolean literals

true and false are the two values of bool.

fn main() {
    print(true)        // true
    print(!false)      // true
}