Change:
<!-- Thank you for filing a bug report! Please provide a short summary of the bug, along with any information you feel relevant to replicating the bug. --I was reviewing some code that uses in a loop to take the contents of a buffer, while leaving the buffer's capacity intact to be reused by subsequent iterations. When I double-checked the actual behaviour of , I was surprised to find that the vector returned by had a much larger capacity than was necessary to hold its contents. Consider this example program: I expected that the and vectors would have similar capacities, since they each only hold one value. Instead, this happened: The single-element vector produced by has a tight capacity of 1, but the single-element vector produced by has a wasteful capacity of 100, which is the same as the original vector's capacity. (The method's documentation doesn't make any explicit promises about the capacity of the returned vector, so this isn't necessarily a bug per se, but it is a surprising behaviour.)
This behaviour seems to have been introduced by , as an explicit optimization of the case, to avoid having to move the elements into a new allocation. That PR notes that the new behaviour is compatible with the existing documentation, and notes some concerns about wastefully reallocating lots of capacity due to an outlier in how long the list gets, but I don't see any discussion of the capacity of the returned vector specifically. At the very least, this behaviour probably deserves some warning in the docs, since the actual behaviour wastes more capacity than the “obvious” implementation would.
label +T-libs
Looking again at the actual documentation, it says this: If the returned vector is “newly allocated”, it's natural to assume that the new allocation would be reasonably tight, if not exact. But in the 0 case, the returned vector isn't newly allocated at all, since it steals its allocation from the existing vector.
When is 0, directly return original vec as here: it's indeed a issue, but I haven't got a better solution, this change will fix the issue, but will also introduce extra copy:
splitoff in don't have this issue:
I think the realistic options are: Document the possibility of unexpected capacity/allocation behaviour when Remove the special handling for , and just use the same code path for and In cases where is unknown, I think it's surprising for 0 and 1 to behave very differently. In cases where the user specifically wants the current behaviour, it may be better for the user to write themselves.

Discussion:
assert_failed(at, self.len()); } <del> if at == 0 { // the new vector can take over the original buffer and avoid the copy return mem::replace( self, Vec::with_capacity_in(self.capacity(), self.allocator().clone()), ); } </del> let other_len = self.len - at; let mut other = Vec::with_capacity_in(other_len, self.allocator().clone());

#[test] fn test_split_off() { let mut vec = vec![1, 2, 3, 4, 5, 6]; <ins> let orig_ptr = vec.as_ptr(); </ins> let orig_capacity = vec.capacity(); <del> let vec2 = vec.split_off(4); </del> <ins> let split_off = vec.split_off(4); </ins> assert_eq!(vec, [1, 2, 3, 4]); <del> assert_eq!(vec2, [5, 6]); </del> <ins> assert_eq!(split_off, [5, 6]); </ins> assert_eq!(vec.capacity(), orig_capacity); <ins> assert_eq!(vec.as_ptr(), orig_ptr); </ins> } #[test] fn test_split_off_take_all() { <del> let mut vec = vec![1, 2, 3, 4, 5, 6]; </del> <ins> // Allocate enough capacity that we can tell whether the split-off vector's // capacity is based on its size, or (incorrectly) on the original capacity. let mut vec = Vec::with_capacity(1000); vec.extend([1, 2, 3, 4, 5, 6]); </ins> let orig_ptr = vec.as_ptr(); let orig_capacity = vec.capacity(); <del> let vec2 = vec.split_off(0); </del> <ins> let split_off = vec.split_off(0); </ins> assert_eq!(vec, []); <del> assert_eq!(vec2, [1, 2, 3, 4, 5, 6]); </del> <ins> assert_eq!(split_off, [1, 2, 3, 4, 5, 6]); </ins> assert_eq!(vec.capacity(), orig_capacity); <del> assert_eq!(vec2.as_ptr(), orig_ptr); </del> <ins> assert_eq!(vec.as_ptr(), orig_ptr); // The split-off vector should be newly-allocated, and should not have // stolen the original vector's allocation. assert!(split_off.capacity() < orig_capacity); assert_ne!(split_off.as_ptr(), orig_ptr); </ins> } #[test]