Listing 2.3, run: integers and floats¶
Rust in Action, run › Chapter 2 › §2.3.1 · the book's file: ch2/ch2-intro-to-numbers.rs ↗
Level: 101 · a companion to Rust in Action, chapter 2
One line: Listing 2.3 prints 20 + 21 + 22 = 63, 1000000000000 and 42 on rustc 1.98.0, exactly as the book shows. The : i64 on one_million looks optional and is not: without it, the pow call does not compile, and with : i32 the result overflows. When the section talks about declaring a type's size in bytes, the type names actually give it in bits.
What the listing prints¶
Nine claims, run¶
Verified output of intro_to_numbers.rs — regenerated by tools/run_examples.py, never hand-typed.
1. 20 + 21 + 22 = 63
twenty is i32; the same 20 added to an i64 is i64
2. i64: 1000000000000
i32: checked_pow(2) is None, because i32::MAX is 2147483647
3. forty_twos is [f32; 3]; an unsuffixed pair is [f64; 2]
4. 42 | 04 | 042.0
5. 24.5_f32.round() = 25, f32::round(24.5) = 25, 24.5_f32.round_ties_even() = 24
6. i16: 16 bits, 2 bytes; i32: 32 bits, 4 bytes; i64: 64 bits, 8 bytes
7. 20 21 text
8. 42 | 42 | forty-two
9. forty_twos[0] = 42, forty_twos.get(3) = None
- Rust infers a type when you give none:
twentygets its type from the sum it joins. Here that isi32, which is also the fallback, so the listing cannot show where the type came from. The same20added to ani64becomes ani64, which shows it. → Type inference - The
: i64onone_millionis needed. 1 000 000² is 10¹², far pasti32::MAX. As ani32,checked_pow(2)returnsNone, and a plainpow(2)panics in a debug build (transcript below). With no annotation and no suffix, the call does not compile at all. → The bill for having a width, Signed overflow - An array has one element type, and its suffixed members choose it.
[42.0, 42f32, 42.0_f32]is[f32; 3], because the unsuffixed42.0takes the type of its neighbours. On their own, two unsuffixed floats fall back tof64. That is what the listing's note means by 32-bit or 64-bit depending on context. Mix anf32with anf64and the array does not compile. → Arrays and slices, Single and double precision {:02}pads to at least two characters with zeros, and42already has two, so in the listing it changes nothing.4.0shows it working, and{:05.1}adds a precision. → The format mini-language24.5_f32.round()needs its suffix, and a path call does not. The book is right that a method call on a float literal needs a concrete type. Writingf32::round(24.5)gives it one through the parameter.roundsends a tie away from zero (25);round_ties_evensends it to the even neighbour (24). → Making a float whole- The number in a type's name counts bits, not bytes. The book says you get used to declaring a type's size in bytes.
i32is 32 bits, andsize_ofreports it as 4 bytes. → Values, Meet the byte - "Conversions are always explicit" is true of numbers only. An
i16does not quietly become ani32: that isE0308, and the compiler suggests.into(). Some other conversions do happen without a call:&Stringbecomes&strwherever a&stris expected. That is deref coercion, and the compiler's list of coercions has no numeric conversion on it. → Coercion,FromandInto, Casting withas - Operator overloading means each pair of types is a separate trait impl.
+works on integers, floats andString + &strbecause each of those pairs has its ownAdd↗ impl.i32 + i64has none, so it does not compile, even though both are integers. → Operators are traits - Indexing starts at 0, and
getasks without the risk of a panic. An index past the end is a panic at run time. When both the array and the index are constants, it is a compile error instead. → Out of bounds is a panic
What the compiler refuses¶
With no type, pow does not compile¶
error[E0689]: can't call method `pow` on ambiguous numeric type `{integer}`
--> pow_on_a_bare_literal.rs:3:32
|
3 | println!("{}", one_million.pow(2));
| ^^^
|
help: you must specify a type for this binding, like `i32`
|
2 | let one_million: i32 = 1_000_000;
| +++++
The fallback to i32 happens too late to pick a method, so the compiler asks for the type. Take its suggestion literally, i32, and you get the next section.
As an i32, the square overflows¶
thread 'main' panicked at …/library/core/src/num/mod.rs:426:5:
attempt to exponentiate with overflow
A release build (rustc -O) has no overflow checks, so it prints the wrapped value -727379968 and exits with status 0. The i64 in the listing avoids both. → Overflow checks, in the glossary
A method on a bare float literal¶
error[E0689]: can't call method `round` on ambiguous numeric type `{float}`
--> round_on_a_bare_float.rs:2:25
|
2 | println!("{}", 24.5.round());
| ^^^^^
|
help: you must specify a concrete type for this numeric value, like `f32`
|
2 | println!("{}", 24.5_f32.round());
| ++++
An f32 and an f64 in one array¶
error[E0308]: mismatched types
--> mixed_float_array.rs:2:36
|
2 | let forty_twos = [42.0, 42f32, 42.0_f64];
| ^^^^^^^^ expected `f32`, found `f64`
No quiet widening¶
error[E0308]: mismatched types
--> i16_into_i32.rs:3:21
|
3 | let long: i32 = short;
| --- ^^^^^ expected `i32`, found `i16`
| |
| expected due to this
|
help: you can convert an `i16` to an `i32`
|
3 | let long: i32 = short.into();
| +++++++
+ between two integer types¶
error[E0308]: mismatched types
--> i32_plus_i64.rs:4:28
|
4 | println!("{}", small + big);
| ^^^ expected `i32`, found `i64`
error[E0277]: cannot add `i64` to `i32`
--> i32_plus_i64.rs:4:26
|
4 | println!("{}", small + big);
| ^ no implementation for `i32 + i64`
|
= help: the trait `Add<i64>` is not implemented for `i32`
A constant index past the end¶
error: this operation will panic at runtime
--> const_index_out_of_bounds.rs:3:23
|
3 | println!("{:02}", forty_twos[3]);
| ^^^^^^^^^^^^^ index out of bounds: the length is 3 but the index is 3
|
= note: `#[deny(unconditional_panic)]` on by default
error: aborting due to 1 previous error
Concepts, keywords, topics¶
| In the listing or the section | Keyword or concept | Lesson here | Normative source |
|---|---|---|---|
let twenty = 20; |
type inference, integer fallback | Type inference | Integer literal expressions ↗ |
let twenty_one: i32 = 21; |
type annotation | What a type annotation does | let statements ↗ |
22i32, 1_000_000 |
literal suffix, digit separator | Writing a number down | Suffixes ↗ |
one_million.pow(2) |
methods on primitives, overflow | Meet the byte · Signed overflow | i64::pow ↗ · checked_pow ↗ |
[42.0, 42f32, 42.0_f32] |
array, float literal, f32/f64 |
Arrays and slices · What a float actually stores | Array expressions ↗ · Floating-point literals ↗ |
{:02} |
format spec: width, fill | The format mini-language | Width ↗ |
forty_twos[0] |
indexing | Arrays and slices | Indexing expressions ↗ |
24.5_f32.round() |
rounding a float | Making a float whole | f32::round ↗ |
the same + for many types |
operator overloading | Operators are traits | Arithmetic operators ↗ |
| explicit conversions | From/Into, as, coercion |
From and Into · Casting with as · Coercion |
Type coercions ↗ |
| many numeric types | integer and float widths | Values · Tables 2.1 and 2.2, run | Numeric types ↗ |
The glossary defines integer fallback, overflow checks, operator overloading, coercion, as cast, array and E0689.
See also¶
- Previous: Listing 2.2, run: variables and functions · next: Listing 2.4, run: base 2, 8 and 16
- Rust in Action, run — the chapter's listings, and a concept index across them
- What
i128is exact about — where to go when eveni64is too narrow
Po polsku¶
Listing 2.3 wypisuje na rustc 1.98.0 dokładnie to, co pokazuje książka. Adnotacja : i64 przy one_million tylko wygląda na opcjonalną: bez niej wywołanie pow się nie kompiluje (E0689, can't call method on ambiguous numeric type), a jako i32 wynik 10¹² przekracza i32::MAX i w kompilacji debug kończy się paniką attempt to exponentiate with overflow. Liczba w nazwie typu to bity, nie bajty: i32 ma 32 bity, czyli 4 bajty.
Tablica ma jeden typ elementów i wybierają go elementy z przyrostkiem: [42.0, 42f32, 42.0_f32] to [f32; 3], a dwie liczby bez przyrostka dają f64. Konwersje liczbowe są zawsze jawne (i16 nie stanie się po cichu i32), ale nie wszystkie konwersje — &String zamienia się w &str bez żadnego wywołania (deref coercion). Przeciążanie operatorów (operator overloading) oznacza osobną implementację cechy Add dla każdej pary typów, dlatego i32 + i64 się nie kompiluje. round zaokrągla połówki od zera (24,5 → 25), a round_ties_even do parzystej (24).
Szukaj po polsku: przepełnienie liczby całkowitej · zaokrąglanie w Ruscie · rust E0689 ambiguous numeric type · rust i32 + i64 cannot add · przeciążanie operatorów