Why doesnt Take<Char<'a>> implements as_str

So basicly i have Chars<'a> and i want to have a &'a str from fist n characters.

let a  = "hello world".chars();
let b  = a.clone().take(4);  

let c  = a.as_str();
println!("{c}");
let c  = b.as_str(); // <<---- This fails to compile because Take<Char<a>> doesnt have as_str
println!("{c}"); 

Why doesnt Take<T> implements everything that T implements
How can i accomplish what i want to do or is it even possible?

Because it's impossible in general. In this case, only Chars knows how to get the underlying string slice, but only Take knows how long this slice should be, and combining this information would require special-casing Take<Chars>, not using some generally-useful approach.

Probably the easiest way would be not using the Chars<'a> at all, but to manually get the necessary index:

let orig = "hello world";
let index = orig.char_indices().nth(4).unwrap().0;
let c = &orig[..index];
println!("{c}"); 

If all you have is Chars, the best bet is probably to get a String and not a &str, by collecting the Take<Chars>.

3 Likes

aah i see. Thanks very much

Char<'a> has as_str in part because it's so cheap: the portion of the &str it has not iterated over is already a valid UTF8 string.

Whereas even if Take<Char<'a>> had access to that &str, it would have to scan it to count characters and valid offsets, because UTF8 is a variable width encoding.

If you just want the ability to get some prefix, try this.

1 Like

Actually come to think of it there are many iterators which has asized underlying data structure. A specialization on Take for iterators whose underlying data size is known doesnt seem far fetched to me. Although im not sure if that is expressable in rust atm

I would imagine Take<std::slice::Iter<'a, T>> have a as_slice method. But Take<Char<'a>> is not that cheap so I don't this it's a really good idea.

Doesnt seem like it. This failed to compile

let a = [1,2,3,4,5,6];
let a_it = a.iter();
let b = a_it.take(4).as_slice();
println!("{b}");
error[E0599]: no method named `as_slice` found for struct `std::iter::Take` in the current scope
  --> src/main.rs:10:26
   |
10 |     let b = a_it.take(4).as_slice();
   |                          ^^^^^^^^ method not found in `std::iter::Take<std::slice::Iter<'_, {integer}>>`

Just saying it's reasonable to have one, not there's already one.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.