Hacker News new | past | comments | ask | show | jobs | submit login

In go, the stdlib impl is actually:

    func Clone[S ~[]E, E any](s S) S {
      if s == nil {
        return nil
      }
      return append(S([]E{}), s...)
    }
    
For comparison, `vec.clone()` in the rust stdlib is:

    pub trait Clone: Sized {
      fn clone(&self) -> Self;
    }

    impl<T: Clone> Clone for Vec<T> {
      fn clone(&self) -> Self {
        <[T]>::to_vec(&**self)
      }
    }
I think the rust one is much easier to read. The go one has an if statement, which means the go one has higher cyclomatic complexity, and is thus harder to understand and reason about.

The rust one does have "&**self", which looks a little strange perhaps, but overall seems simpler than the go one.




What is “&**self” called?


It is so simple it does not have a name. It is simply a double deref + borrow.

Since "deref" can be implemented differently for each type, you cannot know what it does in general, but in this case '*Vec<T>' turns it into a '[T]'.

If you compile in release mode, all of the following implementations of 'clone' will emit identical assembly:

    <[T]>::to_vec(&**self)

    <[T]>::to_vec(&self[..])

    <[T]>::to_vec(self.as_slice())

    self.as_slice().to_vec()
The stdlib picked the coolest looking one. Can't fault them for that.


Honestly I'd have preferred `.as_slice().to_vec()`


It reborrows `*self` als a slice. I prefer The Methode `as_slice` which does the same.


Yeah, that one if statement really melts my brain. /s




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: