Skip to content

← Modules, Visibility, Testing and Docs step 9 of 22

Medium Primitives

The five preludes

A new Rust file can use Vec, Option, String and Iterator without any use line. Those names come from a prelude: a collection of names that name resolution makes available in every module automatically. A name you define or import yourself takes priority over a prelude name with the same spelling.

The Rust Reference lists five preludes. The attribute #![no_implicit_prelude] (placed at the top of a crate or module) turns most of them off for that module and the modules inside it.

prelude what it provides removed by #![no_implicit_prelude]?
standard library Vec, Option, Iterator, functions such as drop; the contents depend on the edition yes
extern the names of crates passed to the compiler, such as std and your dependencies yes
language the primitive types bool, char, str, the integer types and f32/f64, plus built-in attributes such as #[inline] no
macro_use macros brought in by #[macro_use] extern crate some_crate; (still accepted in edition 2024) yes in editions 2018 and later; not in 2015
tool tool namespaces such as clippy and rustfmt, used in attributes like #[rustfmt::skip] yes

In a module with #![no_implicit_prelude] you can still reach the standard library through a path that starts with ::, for example ::std::vec::Vec<u8> or ::std::println!. Plain println! is not found there, and in editions 2018 and later neither is plain std::vec::Vec. With rustc 1.98, some compiler built-in macros such as concat! and stringify! still resolve in such a module.

Edition differences in the standard-library prelude

An edition (2015, 2018, 2021 or 2024) is a per-crate setting that selects a few language rules. One thing it selects is the version of the standard-library prelude:

  • 2015 and 2018 use the same prelude.
  • 2021 adds TryFrom, TryInto and FromIterator. Older code often starts with use std::convert::TryInto;. That line still compiles in a 2021 or 2024 crate. With rustc 1.98 it produces no warning by default; the allow-by-default lint redundant_imports reports it if you enable it.
  • 2024 adds Future and IntoFuture.

These additions were tied to editions because a new prelude trait can break existing code. For example, if your own trait also has a try_into method for i64, then x.try_into() compiles in edition 2018 but fails in edition 2021 with error E0034 ("multiple applicable items in scope"), because both traits are now in scope.

Not every addition waits for a new edition. With rustc 1.98, size_of and the AsyncFn traits are in the prelude of every edition, including 2015.

The task

pub fn needs_import(edition: &str, names: Vec<String>) -> Vec<String>

Return the names from names that are not in scope automatically for the given edition, which are the ones that would need a use (or a full path). Keep them in input order. Keep duplicates. An empty names gives an empty result.

This is a model with a fixed list of names. A name is in scope exactly when it appears in one of these lists:

  • Language prelude (every case): bool, char, str, u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, f32, f64.
  • Standard prelude for "2015", "2018", "2021" and "2024": the 35 names in the starter's V1 constant (AsMut, AsRef, Box, Clone, ..., Unpin, Vec).
  • Added for "2021" and "2024": TryFrom, TryInto, FromIterator.
  • Added for "2024" only: Future, IntoFuture.

Every other name needs an import, including real prelude items the model leaves out, such as drop, size_of and AsyncFn. Comparison is exact and case-sensitive: Vec is in scope, vec and VEC are not.

The edition must match one of the four strings exactly. Any other string, including "none", "" or "2027", models a module with #![no_implicit_prelude]: the standard prelude and both edition additions are absent, but the language prelude remains.

The grader compiles your code with edition 2024, so all five added names are already in scope in your own solution.

Two cases in the tests

Primitive type names never need an import. bool and u32 are in the language prelude, which #![no_implicit_prelude] does not remove.

Frequently used is not the same as in the prelude. HashMap, Rc and Ordering are in no edition's prelude. Without an import, edition 2024 reports E0425 ("cannot find type HashMap in this scope"). They need use std::collections::HashMap;, use std::rc::Rc; and use std::cmp::Ordering;.

Shadowing a prelude name

Because your own names take priority, a glob import can replace a prelude name without any warning. If my_prelude exports a type alias named Result, then after use my_prelude::*; the name Result in that module refers to the alias, not to std::result::Result.