Skip to content

Instantly share code, notes, and snippets.

@jordanorelli
Created November 29, 2021 01:51
Show Gist options
  • Save jordanorelli/bccd1be0884681a9463ceb9f234f27c0 to your computer and use it in GitHub Desktop.
Save jordanorelli/bccd1be0884681a9463ceb9f234f27c0 to your computer and use it in GitHub Desktop.
a read-only reference type with generics in Go
package main
import (
"fmt"
)
// ref is a reference to a value. A reference can read that
// value but not alter it.
type ref[V any] struct {
v *V
}
// mkref creates a ref from a pointer
func mkref[V any](ptr *V) ref[V] {
return ref[V]{v: ptr}
}
// Val gives the value of a reference
func (r ref[V]) Val() V { return *r.v }
func (r ref[V]) String() string { return fmt.Sprint(*r.v) }
func changeP(s *string, v string) {
fmt.Printf("canChange sees: %s\n", *s)
*s = v
fmt.Printf("canChange changes value to %s\n", *s)
}
func changeRef(r ref[string], v string) {
fmt.Printf("changeRef sees value: %s\n", r.Val())
// this is a compile-time error:
// r.Val() = v
// this doesn't change anything:
rv := r.Val()
rv = v
fmt.Printf("changeRef attempts to change value to %s\n", rv)
}
type whatever struct {
name ref[string]
}
func (w whatever) String() string { return w.name.Val() }
func main() {
name := "jordan"
nameRef := mkref(&name)
w := whatever{name: mkref(&name)}
fmt.Printf("name: %s\n", name)
fmt.Printf("nameRef: %s\n", nameRef.Val())
// changes to the value are reflected in the reference
name = "orelli"
fmt.Printf("name: %s\n", name)
fmt.Printf("nameRef: %s\n", nameRef.Val())
// the pointer to the value is the mutable reference
changeP(&name, "poop")
fmt.Printf("name: %s\n", name)
fmt.Printf("nameRef: %s\n", nameRef.Val())
changeRef(nameRef, "mittens")
fmt.Printf("name: %s\n", name)
fmt.Printf("nameRef: %s\n", nameRef.Val())
fmt.Println(w)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment