1. What is the role of Cargo.lock in a Rust project?
Answer: It records the exact resolved versions and checksums of all dependencies, ensuring reproducible builds.
Cargo.tomldeclares dependency requirements (version ranges like"1.2.3"or"^1.0").Cargo.lockpins the exact versions that were resolved — so everyone (and every CI run) builds with identical dependency versions, eliminating “works on my machine.”
# Cargo.lock snippet
[[package]]
name = "serde"
version = "1.0.200" # exact, frozen
Behavior nuances:
- Binaries: commit
Cargo.lock— reproducibility matters. - Libraries: typically don’t commit it — downstream consumers resolve their own (crates are compiled in dependency-context). Cargo still uses it locally if present.
The interview answer: Cargo.lock pins exact dependency versions + checksums for reproducible, deterministic builds.
Answer:
It records the exact resolved versions and checksums of all dependencies, ensuring reproducible builds.
Cargo.tomldeclares dependency requirements (version ranges like"1.2.3"or"^1.0").Cargo.lockpins the exact versions that were resolved — so everyone (and every CI run) builds with identical dependency versions, eliminating “works on my machine.”
# Cargo.lock snippet
[[package]]
name = "serde"
version = "1.0.200" # exact, frozen
Behavior nuances:
- Binaries: commit
Cargo.lock— reproducibility matters. - Libraries: typically don’t commit it — downstream consumers resolve their own (crates are compiled in dependency-context). Cargo still uses it locally if present.
The interview answer: Cargo.lock pins exact dependency versions + checksums for reproducible, deterministic builds.
2. What does the pub(crate) visibility modifier mean?
Answer: The item is visible everywhere inside the current crate, but hidden from external crates.
pub(crate) is a scoped publicity:
pub(crate) fn helper() { /* ... */ } // usable across the crate, not exported
- Items with no modifier are private to their module.
- Items with
pubare exported to all downstream crates. pub(crate)sits in between: public within the crate (any module can use it), but not part of the public API external crates can import.
Use it for internal APIs shared between modules that shouldn’t leak into the public interface. The interview answer: visible crate-wide, but not exported to external crates.
Answer:
The item is visible everywhere inside the current crate, but hidden from external crates.
pub(crate) is a scoped publicity:
pub(crate) fn helper() { /* ... */ } // usable across the crate, not exported
- Items with no modifier are private to their module.
- Items with
pubare exported to all downstream crates. pub(crate)sits in between: public within the crate (any module can use it), but not part of the public API external crates can import.
Use it for internal APIs shared between modules that shouldn’t leak into the public interface. The interview answer: visible crate-wide, but not exported to external crates.
3. What is the difference between const and static items in Rust?
Answer: const is inlined at compile time (no address); static is a fixed memory location shared program-wide.
const MAX: u32 = 100; // value inlined wherever used
static APP_NAME: &str = "app"; // one fixed address in the binary
static mut COUNTER: i32 = 0; // mutable static (requires unsafe to touch)
const: a compile-time constant. Every use is replaced by its value — no storage of its own. Always immutable. Only constant expressions.static: a true global variable at a fixed memory address, existing for the program’s lifetime. Can bemut(but accessing a mutable static requiresunsafeand risks races) orSync/Send-typed.
When to use which: const for constants/limits; static when you need a single address, a global singleton, or 'static-lifetime data. The interview answer: const = inlined compile-time value; static = fixed-address global storage shared across the program.
Answer:
const is inlined at compile time (no address); static is a fixed memory location shared program-wide.
const MAX: u32 = 100; // value inlined wherever used
static APP_NAME: &str = "app"; // one fixed address in the binary
static mut COUNTER: i32 = 0; // mutable static (requires unsafe to touch)
const: a compile-time constant. Every use is replaced by its value — no storage of its own. Always immutable. Only constant expressions.static: a true global variable at a fixed memory address, existing for the program’s lifetime. Can bemut(but accessing a mutable static requiresunsafeand risks races) orSync/Send-typed.
When to use which: const for constants/limits; static when you need a single address, a global singleton, or 'static-lifetime data. The interview answer: const = inlined compile-time value; static = fixed-address global storage shared across the program.
4. What does the #[inline] attribute suggest to the compiler?
Answer: It hints the compiler to replace calls to the function with the function body, eliminating call overhead.
#[inline] is a suggestion (not a command) that the function be inlined at call sites:
- Pros: removes call/return overhead, enables further optimization across the call boundary.
- Cons: grows binary size if inlined in many places.
Why it exists: without it, the compiler may refuse to inline across crate boundaries (public functions in one crate called from another), because the body isn’t visible. #[inline] (or #[inline(always)] for a stronger hint) makes the function’s body available for inlining even cross-crate. Used for small, hot functions (accessors, hot loop helpers). The interview answer: a hint to inline the function body at call sites, reducing call overhead at the cost of binary size.
Answer:
It hints the compiler to replace calls to the function with the function body, eliminating call overhead.
#[inline] is a suggestion (not a command) that the function be inlined at call sites:
- Pros: removes call/return overhead, enables further optimization across the call boundary.
- Cons: grows binary size if inlined in many places.
Why it exists: without it, the compiler may refuse to inline across crate boundaries (public functions in one crate called from another), because the body isn’t visible. #[inline] (or #[inline(always)] for a stronger hint) makes the function’s body available for inlining even cross-crate. Used for small, hot functions (accessors, hot loop helpers). The interview answer: a hint to inline the function body at call sites, reducing call overhead at the cost of binary size.
5. What does the #[repr(C)] attribute do when applied to a Rust struct?
Answer: It forces C-compatible memory layout (field order and alignment) for FFI interoperability.
By default, Rust is free to reorder struct fields to minimize padding — the layout is unspecified. #[repr(C)] locks the layout to C’s rules: fields in declaration order, standard alignment/padding:
#[repr(C)]
struct Point { x: f64, y: f64 } // exact C layout, guaranteed
Why it matters:
- FFI: passing a struct to/from C code requires identical layout on both sides; without
repr(C), the Rust side could arrange fields differently. - Stable layout: guarantees field offsets for unsafe code, manual serialization, or reading raw bytes.
You also get #[repr(u8)]/#[repr(i32)] etc. to control enum discriminant size, and #[repr(align(N))] for alignment. The interview answer: repr(C) forces C-compatible field ordering/padding, essential for FFI and stable layout guarantees.
Answer:
It forces C-compatible memory layout (field order and alignment) for FFI interoperability.
By default, Rust is free to reorder struct fields to minimize padding — the layout is unspecified. #[repr(C)] locks the layout to C’s rules: fields in declaration order, standard alignment/padding:
#[repr(C)]
struct Point { x: f64, y: f64 } // exact C layout, guaranteed
Why it matters:
- FFI: passing a struct to/from C code requires identical layout on both sides; without
repr(C), the Rust side could arrange fields differently. - Stable layout: guarantees field offsets for unsafe code, manual serialization, or reading raw bytes.
You also get #[repr(u8)]/#[repr(i32)] etc. to control enum discriminant size, and #[repr(align(N))] for alignment. The interview answer: repr(C) forces C-compatible field ordering/padding, essential for FFI and stable layout guarantees.
6. What is the function of the include_str! macro?
Answer: It embeds a file’s contents into the binary at compile time as a &'static str.
include_str!("path/to/file.txt") reads the file at compile time and bakes its UTF-8 text directly into the executable:
const TEMPLATE: &str = include_str!("templates/email.html");
let schema: &'static str = include_str!("schema.sql");
Key points:
- Compile-time — the file must exist when building; the string is baked into the binary (no runtime file I/O, no deployment dependency).
- Returns
&'static str(lifetime forever). - Sibling macros:
include_bytes!(raw bytes as&'static [u8]),include!(include a Rust source file).
Use it for templates, SQL, embedded assets, and config that should ship inside the executable. The interview answer: include_str! reads a file at compile time and embeds its contents as a &'static str in the binary.
Answer:
It embeds a file’s contents into the binary at compile time as a &'static str.
include_str!("path/to/file.txt") reads the file at compile time and bakes its UTF-8 text directly into the executable:
const TEMPLATE: &str = include_str!("templates/email.html");
let schema: &'static str = include_str!("schema.sql");
Key points:
- Compile-time — the file must exist when building; the string is baked into the binary (no runtime file I/O, no deployment dependency).
- Returns
&'static str(lifetime forever). - Sibling macros:
include_bytes!(raw bytes as&'static [u8]),include!(include a Rust source file).
Use it for templates, SQL, embedded assets, and config that should ship inside the executable. The interview answer: include_str! reads a file at compile time and embeds its contents as a &'static str in the binary.
7. What is the purpose of the non_exhaustive attribute on enums or structs?
Answer: It tells downstream crates the type may gain new variants/fields, forcing them to write wildcard arms (_ => ...) and blocking direct struct construction.
#[non_exhaustive] on a public type:
- Enums: downstream crates can’t match exhaustively without a wildcard
_ => ...arm — so the library can add variants later without breaking downstream matches. - Structs: downstream crates can’t construct the struct literally (missing fields would be an error), and can’t match fields exhaustively — so the library can add fields later without breaking construction.
#[non_exhaustive]
pub enum Error { Io, Parse } // downstream must add `_ =>` arm
It’s a semver-stability tool for library authors: they can evolve the type without committing to a breaking change, at the cost of forcing downstream code to be non-exhaustive. The interview answer: #[non_exhaustive] forces downstream crates to add wildcard arms / avoid literal construction, letting the library add variants or fields in future versions without breaking them.
Answer:
It tells downstream crates the type may gain new variants/fields, forcing them to write wildcard arms (_ => ...) and blocking direct struct construction.
#[non_exhaustive] on a public type:
- Enums: downstream crates can’t match exhaustively without a wildcard
_ => ...arm — so the library can add variants later without breaking downstream matches. - Structs: downstream crates can’t construct the struct literally (missing fields would be an error), and can’t match fields exhaustively — so the library can add fields later without breaking construction.
#[non_exhaustive]
pub enum Error { Io, Parse } // downstream must add `_ =>` arm
It’s a semver-stability tool for library authors: they can evolve the type without committing to a breaking change, at the cost of forcing downstream code to be non-exhaustive. The interview answer: #[non_exhaustive] forces downstream crates to add wildcard arms / avoid literal construction, letting the library add variants or fields in future versions without breaking them.
8. What does cfg(target_os = “windows”) do when used as an attribute?
Answer: It conditionally compiles the annotated item only when building for Windows.
#[cfg(...)] gates items on compile-time conditions:
#[cfg(target_os = "windows")]
fn platform_specific() { /* Windows-only code */ }
#[cfg(not(target_os = "windows"))]
fn platform_specific() { /* other platforms */ }
target_osis a compile-time configuration value set by the target triple ("windows","linux","macos","android", …).- Items whose
cfgcondition is false are stripped from the build entirely (not compiled).
Other common cfg keys: target_arch ("x86_64", "aarch64"), debug_assertions, feature = "..." (Cargo features), unix/windows aliases. This is how Rust does cross-platform conditional code. The interview answer: #[cfg(target_os = "windows")] compiles the item only for Windows targets — conditional compilation.
Answer:
It conditionally compiles the annotated item only when building for Windows.
#[cfg(...)] gates items on compile-time conditions:
#[cfg(target_os = "windows")]
fn platform_specific() { /* Windows-only code */ }
#[cfg(not(target_os = "windows"))]
fn platform_specific() { /* other platforms */ }
target_osis a compile-time configuration value set by the target triple ("windows","linux","macos","android", …).- Items whose
cfgcondition is false are stripped from the build entirely (not compiled).
Other common cfg keys: target_arch ("x86_64", "aarch64"), debug_assertions, feature = "..." (Cargo features), unix/windows aliases. This is how Rust does cross-platform conditional code. The interview answer: #[cfg(target_os = "windows")] compiles the item only for Windows targets — conditional compilation.
Premium Content
Unlock Modules & Tooling and all premium lessons with a subscription.
From ₹199.99/year — See plans