We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Generics and Traits step 12 of 24
Expose a string view with Deref
Implement Deref<Target = str> for the supplied Username wrapper. Keep
stats and shout_len unchanged so the existing method calls and borrowed
argument work through your implementation.
pub struct Username(pub String);
pub fn stats(names: Vec<String>) -> Vec<usize>
For each input name, stats returns the sum of:
- Its original UTF-8 byte length, from
u.len(). - Its number of Unicode scalar values, from
u.chars().count(). - Its uppercase UTF-8 byte length, from the supplied
shout_len(&u).
Return one result per name in input order. Preserve duplicates. Empty input
produces an empty vector, and an empty name produces zero. Names can contain
arbitrary Unicode, whitespace and control characters; do not trim or normalize
them. Input sizes and the sums fit in usize.
Bytes and scalar values are different counts
| Name | Original bytes | Scalar values | Uppercase bytes | Result |
|---|---|---|---|---|
ada |
3 | 3 | 3 (ADA) |
9 |
héllo |
6 | 5 | 6 (HÉLLO) |
17 |
ß |
2 | 1 | 2 (SS) |
5 |
chars() counts Unicode scalar values, not user-perceived characters. For
example, an e followed by a combining acute accent has two scalar values.
An emoji sequence may also contain several. String length counts bytes.
The helper uses Rust's str::to_uppercase(), which performs Unicode uppercase
mapping without a locale setting. A mapping may expand one scalar value into
several, and the byte length can change too. Use the helper rather than an
ASCII-only conversion. Unicode tables can change with Rust versions; the
examples here were checked with Rust 1.98.1.
Borrow the inner string
Deref has an associated Target and a method returning a reference to it.
This complete example shows the same pattern with a separate wrapper:
use std::ops::Deref;
struct Text(String);
impl Deref for Text {
type Target = str;
fn deref(&self) -> &Self::Target {
self.0.as_str()
}
}
fn byte_len(text: &str) -> usize {
text.len()
}
fn main() {
let text = Text(String::from("héllo"));
assert_eq!(text.len(), 6);
assert_eq!(text.chars().count(), 5);
assert_eq!(byte_len(&text), 6);
}
Returning &self.0 also works: the expected &str lets Rust coerce the
borrowed String to its string slice. Both forms borrow existing storage;
neither clones the string. The reference cannot outlive the borrow of the
wrapper.
Target = str is a requirement of this exercise, not a rule that every
dereference target must be unsized. Choosing String would permit a further
dereference to str, but would expose a different target API. The output
tests alone do not distinguish those choices.
Two uses of Deref in the starter
The len() and chars() calls use method lookup: Rust can follow the
wrapper's dereference target to find shared str methods. The shout_len
call instead has an expected &str argument type, so &Username can undergo
deref coercion there. Before your implementation exists, those methods are
missing and the argument has the wrong type.
Keep shout_len(&u). Writing shout_len(&*u) also type-checks, but Clippy's
explicit_auto_deref warning identifies the unnecessary explicit step in
this call. That does not make explicit dereferencing wrong everywhere.
Generic trait bounds are a separate issue: a wrapper does not gain all of
its target's trait implementations. A generic call that infers the wrapper
type may therefore fail where a concrete &str parameter accepts it.
Providing an explicit target type can sometimes supply the needed coercion
context; there is no automatic search through dereference targets to satisfy
an arbitrary trait bound.
Choose implicit access deliberately
A dereference implementation becomes part of the wrapper's public API. It should be cheap, unsurprising and free of unexpected failures, because callers may invoke it implicitly. These are design expectations, not compiler guarantees: custom implementations can be costly or panic.
String, Vec and smart pointers demonstrate useful dereference APIs. A
domain wrapper may instead benefit from an explicit accessor, especially if
target methods would conflict with its own meaning. In this exercise, add
the requested trait implementation rather than new inherent len or chars
methods. A new method could delegate faithfully or change the behavior, but
neither would practice the missing dereference implementation.
Your code, saved here
Sign in to access your accepted solutions and saved draft history. You can keep reading the lesson without an account.
Sign in to your accountStuck?
Rust reference solution
Sign in to track your attempts toward unlocking the reference solution.