unit: add Copy method and documentation to avoid unexpected sharing
MODIFY
unit/unit_test.go
unit/unit_test.go
@@ -10,7 +10,7 @@ import (
"testing"
)
-// ether is a non-existant unit used for testing.
+// ether is a non-existent unit used for testing.
type ether float64
func (e ether) Unit() *Unit {
@@ -110,6 +110,21 @@ func TestFormat(t *testing.T) {
}
}
+func TestCopy(t *testing.T) {
+ t.Parallel()
+ for _, ts := range formatTests {
+ u := ts.unit.Unit()
+ if len(u.Dimensions()) == 0 {
+ continue
+ }
+ c := u.Copy()
+ c.Mul(c)
+ if DimensionsMatch(u, c) {
+ t.Errorf("dimensions match after mutating copy of %v: %v == %v", u, u.Dimensions(), c.Dimensions())
+ }
+ }
+}
+
func TestGoStringFormat(t *testing.T) {
t.Parallel()
expect1 := `&unit.Unit{dimensions:unit.Dimensions{4:2, 7:-1}, value:6.62606957e-34}`

MODIFY
unit/unittype.go
unit/unittype.go
@@ -283,11 +283,21 @@ func (u *Unit) Add(uniter Uniter) *Unit {
return u
}
-// Unit implements the Uniter interface
+// Unit implements the Uniter interface, returning the receiver. If a
+// copy of the receiver is required, use the Copy method.
func (u *Unit) Unit() *Unit {
return u
}
+// Copy returns a copy of the Unit that can be mutated without the change
+// being reflected in the original value.
+func (u *Unit) Copy() *Unit {
+ return &Unit{
+ dimensions: u.dimensions.clone(),
+ value: u.value,
+ }
+}
+
// Mul multiply the receiver by the input changing the dimensions
// of the receiver as appropriate. The input is not changed.
func (u *Unit) Mul(uniter Uniter) *Unit {

unit: add Copy method and documentation to avoid unexpected sharing