It's mainly come up for me when across struct boundaries (struct holds a &mut Something and you're in a &mut self method). I wouldn't say "often".
Here, you're really wanting to mutate the pointer to the slice/data (advance by one) and the number of elements in the slice (decrease by one), and both of those are held in the wide pointer to the slice (&mut [T]). So, &mut &mut [T] to mutate the &mut [T].
A simple iterator implementation for a slice reference (with no other supporting state) can be implemented in a similar way:
Heh. Yes, it's a special case useful for this use in particular. It would be sound for &mut to other ZSTs [1] too, as they can never actually alias memory.
In case it's useful to spell out for you or others, when you have a lifetime beneath a &mut, you can't change the inner lifetime:
// vv 'a can be soundly shortened (is covariant)
&'a mut &'b mut [T]
// ^^ 'b cannot sound change at all (is invariant)
And you can't access the longer inner lifetime as such through the shorter outer lifetime:
fn foo<'a, 'b>(shared: &'a &'b [u8], uniq: &'a mut &'b mut [u8]) {
// works because `&_` implements `Copy`
let _: &'b [u8] = *shared;
// this works because conceptually you copied out the inner reference
// and then took the reference
let _: &'b u8 = &shared[0];
// fails because `&mut _` does *not* implement `Copy`
// let _: &'b mut [u8] = *uniq;
// fails because your access is capped to the shortest lifetime in the
// access path (nothing could be copied)
// let _: &'b u8 = &uniq[0];
}
So to get ahold of the &'b mut [_] (so you can return the appropriate item type [2], say), you need to get it out from behind the outer &mut somehow. &mut [] being default allows you to do so with mem::take.
Oh, I was unclear. My surprise was that &mut [T] had a default. But of course, that's because [] is a ZST and you can reasonably do &mut [] to instantiate a slice fat pointer. This means that we could technically even implement Default for any trait fat pointer for an object-safe trait that's defined for (), for example, which is interesting (not that I'm saying that we should).
Err, mea culpa, [] (the type) isn't a ZST, it's a DST; [] (the value) just happens to not alias anything. But the non-aliasing reasoning about ZSTs stands.
You can, or for anything you store statically (or promote) really. But for the &mut case, you need unsafe as no references to ZSTs in std are Default, and the &mut which are ([T], str) are not Sized and thus cannot be coerced into a dyn Trait.
For the boxed/owned case, any implementer that's also Default will do. And, come to think of it, if you have a constructable ZST that implements the trait in question, you might as well just return the Box<dyn Trait> version, as that won't actually allocate for ZSTs. Then the caller can make any &dyn Trait or &mut dyn Trait as they wish (though they won't be &'static _).