Repository navigation
Tracking Issue for split_array #90091
Description
Activity
- addedC-tracking-issueCategory: An issue tracking the progress of sth. like the implementation of an RFCCategory: An issue tracking the progress of sth. like the implementation of an RFCT-libs-api[DEPRECATED; DO NOT USE][DEPRECATED; DO NOT USE]
on Oct 20, 2021 Hmm. Panicking if
M > slice.len(), rather than returning aResult/Option, seems a bit surprising to me. I guess it's consistent withsplit_at, but on the other hand inconsistent with eg.split_first.Reacted by Brendan Zabarauskas, Xiretza, Michał Nazarewicz, Thalia Archibald, Chris de Claverie, Nathaniel Bennett, Mariusz Pawelski, Martin Habovštiak, Kornel, Maurits van Riezen and 2 moreFor the slice versions of these, I think it's important that they not only offer
-> (&[T; N], &[T]), but also-> (&[T], &[T; N]). (This is basically the same as how there's bothas_chunksandas_rchunks, see #78818.)That might open up new naming possibilities too. To spitball:
split_prefix: &[T] -> (&[T; N], &[T])andsplit_suffix: &[T] -> (&[T], &[T; N])
Reacted by Jonas Platte, Johannes Dahlström, Brendan Zabarauskas and John SchugI agree that should exist, but I think it should be named
rsplit_arraysince there's already a bunch of split functions whose "from the end" variations are all calledrsplit*.Reacted by Michael Pfaff and Esper ThomsonI'd argue for local consistency over global consistency. In the case of slice we already have methods following both conventions, but the methods following the
_prefix_suffixconvention are related to stripping, where as the split methods all currently follow thesplitrsplitconvention, so I lean towards keeping the current names.Reacted by Luca Bruno, Michael Pfaff and Ellen Emilia Anna ZscheileShould there also be a shorthand API for
slice[a..].split_array_ref::<B>()(the array version of&slice[a..(a+B)])?I think that the result should be an Option. This would allow us to properly handle splitting in case, the number of elements is lesser than the given contant.
impl<T, const N: usize> [T; N] { pub fn split_array_ref<const M: usize>(&self) -> Option<(&[T; M], &[T])>; pub fn split_array_mut<const M: usize>(&mut self) -> Option<(&mut [T; M], &mut [T])>; pub fn rsplit_array_ref<const M: usize>(&self) -> Option<(&[T], &[T; M])>; pub fn rsplit_array_mut<const M: usize>(&mut self) -> Option<(&mut [T], &mut [T; M])>; }
I've been looking an api like that. However, it would be great to add a proper handling of cases, where split can't happen.
Consider
[1,2,3].split_array_ref<4>().is_none(); /// Would make sense if the split fails /// It's useful for network code, to check if prefix has length at least 4 to decode the message. /// This code can avoid any unwraps, because `u32::from_le_bytes` need array of 4 elements as input. if let Some((left, _) = [1,2,3,4,5].split_array_ref<4>() { println!("{}", u32::from_le_bytes(left)); }
Reacted by Askar Safin, Maurits van Riezen and João Marcossplit_atdoesn't return anOption.split_atdoesn't return anOption.Yes, that's unfortunate. I think it would be great to add
try_split_atapi. This would simplify at lot of code.impl<T, const N: usize> [T; N] { pub fn try_split_at(&self, mid: usize) -> Option<&[T], &[T]> pub fn try_split_array_ref<const M: usize>(&self) -> Option<(&[T; M], &[T])>; pub fn try_split_array_mut<const M: usize>(&mut self) -> Option<(&mut [T; M], &mut [T])>; pub fn try_rsplit_array_ref<const M: usize>(&self) -> Option<(&[T], &[T; M])>; pub fn try_rsplit_array_mut<const M: usize>(&mut self) -> Option<(&mut [T], &mut [T; M])>; }For example:
Currently, I have to write code like this to use the api:let ary = [127,0,0,1,55,66]; if ary.len() >= 4 { let (ip,_) = ary.split_at(4); ///. ... }
I think it would be much cleaner to write it in a declarative way, which avoid hidden unwraps of getting a slice.
let ary = [127,0,0,1,55,66]; if let Some((ip,_)) = ary.try_split_at(4) { /// ... }
Or even better
let ary = [127,0,0,1,55,66]; if let Some((ip,_)) = ary.try_split_array_ref<4>() { /// This makes ip a reference to 4 bytes array. /// ... }
Reacted by Gilad Naaman, Jasha Sommer-Simpson, Tony Arcieri, João Marcos and Joe Birr-Pixtoncc #95198, which proposes doing this more like the
split_firstfamily of things.Those naturally would return
Option, the same way thatfirst&split_firstreturnOptiontoday.Reacted by KornelI definitely want infallible (fail at compile time) split methods on arrays. I want to be able to cut arrays up into smaller array chunks without any bounds checks at runtime. I know there are issues currently that won't allow this API today. But I think we should aim for a future where we can do that.
Being able to parse the content of arrays without paying more bounds checks or code bloat than needed is definitely desired both for readability and performance.
([0u8; 100]).split_array_ref::<10>().expect("out of bounds, will never happen)does not look nice and has a lot of code paths that we already know won't happen. If it was a compile time error we would not accidentally create bugs where the10was made into a too large number.Reacted by Ellen Emilia Anna Zscheile, Michał Nazarewicz, Kaido Kert, David Hoppenbrouwers, John Schug, Chris Beck, Angel Pineda, Khyber Sen, Trevor Gross and Alyssa Haroldsenimpl<T, const N: usize> [T; N] { pub fn try_split_array_ref<const M: usize>(&self) -> Option<(&[T; M], &[T])>; }
This makes no sense IMO 🤔 Because the only time it would ever be
Noneshould be found at compile time. I know that's not possible now. But why introduce a large API surface and use up a bunch of good method names for something that's (hopefully)? a temporary limitation.Reacted by Martin Habovštiak, Michał Nazarewicz, David Hoppenbrouwers, John Schug, Chris Beck and Khyber SenI agree with the comments above that the methods on
&[T]should returnOptions, but as @faern said this makes no sense on arrays, where all size checks are known at compile time. In my opinion the API would ideally look like this (note also thersplit_methods on arrays, for completeness):impl<T, const N: usize> [T; N] { pub fn split_array<const M: usize>(self) -> ([T; M], [T; N - M]); pub fn split_array_ref<const M: usize>(&self) -> (&[T; M], &[T; N - M]); pub fn split_array_mut<const M: usize>(&mut self) -> (&mut [T; M], &mut [T; N - M]); pub fn rsplit_array_ref<const M: usize>(&self) -> (&[T; N - M], &[T; M]); pub fn rsplit_array_mut<const M: usize>(&mut self) -> (&mut [T; N - M], &mut [T; M]); } impl<T> [T] { pub fn split_array_ref<const N: usize>(&self) -> Option<(&[T; N], &[T])>; pub fn split_array_mut<const N: usize>(&mut self) -> Option<(&mut [T; N], &mut [T])>; pub fn rsplit_array_ref<const N: usize>(&self) -> Option<(&[T], &[T; N])>; pub fn rsplit_array_mut<const N: usize>(&mut self) -> Option<(&mut [T], &mut [T; N])>; }
But as noted in the OP, this requires more advanced const generics features. The alternative array API (returning slices for the "rest") would be possible today, but I think it'd be better to wait until the "proper" solution is possible rather than stabilizing something suboptimal.
Reacted by Teodor Tanasoaia, Johannes Dahlström, Imbris, Linus Färnstrand, BennD, Ellen Emilia Anna Zscheile, Michał Nazarewicz, George Bateman, Askar Safin, Trevor Gross and 9 moreReacted by Max Verevkin and Maarten de Vries23 remaining items
With those methods in FCP (#117561 (comment)), nominating this one for libs-api to consider whether they'd like to see these ones deleted from nightly.Err, I should read better. https://github.com/rust-lang/rust/pull/117561/files#diff-e8ccaf64ce21f955ccebef33b52158631493a6f0966815a2ebc142d7cd2b5e06L2024 is removing these methods.
- addedI-libs-api-nominated[DEPRECATED; DO NOT USE][DEPRECATED; DO NOT USE]and removedI-libs-api-nominated[DEPRECATED; DO NOT USE][DEPRECATED; DO NOT USE]
on Jan 11, 2024 - linked a pull request that will close this issueStabilize `slice_first_last_chunk` #117561
on Jan 11, 2024 - added a commit that references this issue
on Jan 20, 2024 Oh, that's my fault -- I saw that it removed
split_array_refand such and thought it was everything.Oh, no I only removed the slice components. I know we want a different API but figured that would just be a rework of this implementation.
But maybe it’s better to start something new with a clean tracking history. I can submit a PR to remove if so.
Reacted by klensy- added a commit that references this issue
on Jan 21, 2024 Haven't seen it linked here, the
arrayrefcrate provides a way to do this.- addedT-libsRelevant to the library team, which will review and decide on the PR/issue.Relevant to the library team, which will review and decide on the PR/issue.and removedT-libs-api[DEPRECATED; DO NOT USE][DEPRECATED; DO NOT USE]
on Aug 12, 2026
View all comments
Feature gate:
#![feature(split_array)]This is a tracking issue for splitting slices and arrays into constant-length arrays.
Public API
Similar functions for slices have already been stabilized as:
See #111774
Unresolved Questions
[T; N - M], like so:However, const generics is not powerful enough for this today. See #83233 (comment) and #83233 (comment).