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
2in0b102(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
u8or au8?, the literal is au8. When the context expects anf64or anf64?, the literal is anf64. - 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
u8or au8?, the literals in the group areu8s. If one is anf64, anf64?or a float literal, they aref64s. These are the groups:- the two operands of an arithmetic operator or a comparison, such as
+,<or== - the operands of a comparison chain
- the elements of an array literal
- the branches of an
ifor anif let, or the arms of amatch
- the two operands of an arithmetic operator or a comparison, such as
- 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
letor aconst - 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
returnvalue 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
matchtests, for a literal in a pattern - the expected type of a loop, for each
breakvalue - the expected type of a block, for its last expression
- the expected type of an
ifor amatch, 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. So1.and.5are errors (E0101). - An exponent is
eorE, 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
f64nearest to the literal. A literal so large that it rounds to infinity is an error (E0103). A literal too small for anf64, such as1e-400, becomes0.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, au8, anf64, abool, acharor astring(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\xbyte escape. - A
\uescape 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
}
Sisu