diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-16 19:23:18 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-16 19:23:18 +0000 |
commit | 43a123c1ae6613b3efeed291fa552ecd909d3acf (patch) | |
tree | fd92518b7024bc74031f78a1cf9e454b65e73665 /test/typeparam/settable.go | |
parent | Initial commit. (diff) | |
download | golang-1.20-upstream.tar.xz golang-1.20-upstream.zip |
Adding upstream version 1.20.14.upstream/1.20.14upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'test/typeparam/settable.go')
-rw-r--r-- | test/typeparam/settable.go | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/test/typeparam/settable.go b/test/typeparam/settable.go new file mode 100644 index 0000000..56cf367 --- /dev/null +++ b/test/typeparam/settable.go @@ -0,0 +1,123 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "fmt" + "strconv" +) + +// Various implementations of fromStrings(). + +type Setter[B any] interface { + Set(string) + *B +} + +// Takes two type parameters where PT = *T +func fromStrings1[T any, PT Setter[T]](s []string) []T { + result := make([]T, len(s)) + for i, v := range s { + // The type of &result[i] is *T which is in the type list + // of Setter, so we can convert it to PT. + p := PT(&result[i]) + // PT has a Set method. + p.Set(v) + } + return result +} + +func fromStrings1a[T any, PT Setter[T]](s []string) []PT { + result := make([]PT, len(s)) + for i, v := range s { + // The type new(T) is *T which is in the type list + // of Setter, so we can convert it to PT. + result[i] = PT(new(T)) + p := result[i] + // PT has a Set method. + p.Set(v) + } + return result +} + +// Takes one type parameter and a set function +func fromStrings2[T any](s []string, set func(*T, string)) []T { + results := make([]T, len(s)) + for i, v := range s { + set(&results[i], v) + } + return results +} + +type Setter2 interface { + Set(string) +} + +// Takes only one type parameter, but causes a panic (see below) +func fromStrings3[T Setter2](s []string) []T { + results := make([]T, len(s)) + for i, v := range s { + // Panics if T is a pointer type because receiver is T(nil). + results[i].Set(v) + } + return results +} + +// Two concrete types with the appropriate Set method. + +type SettableInt int + +func (p *SettableInt) Set(s string) { + i, err := strconv.Atoi(s) + if err != nil { + panic(err) + } + *p = SettableInt(i) +} + +type SettableString struct { + s string +} + +func (x *SettableString) Set(s string) { + x.s = s +} + +func main() { + s := fromStrings1[SettableInt, *SettableInt]([]string{"1"}) + if len(s) != 1 || s[0] != 1 { + panic(fmt.Sprintf("got %v, want %v", s, []int{1})) + } + + s2 := fromStrings1a[SettableInt, *SettableInt]([]string{"1"}) + if len(s2) != 1 || *s2[0] != 1 { + x := 1 + panic(fmt.Sprintf("got %v, want %v", s2, []*int{&x})) + } + + // Test out constraint type inference, which should determine that the second + // type param is *SettableString. + ps := fromStrings1[SettableString]([]string{"x", "y"}) + if len(ps) != 2 || ps[0] != (SettableString{"x"}) || ps[1] != (SettableString{"y"}) { + panic(s) + } + + s = fromStrings2([]string{"1"}, func(p *SettableInt, s string) { p.Set(s) }) + if len(s) != 1 || s[0] != 1 { + panic(fmt.Sprintf("got %v, want %v", s, []int{1})) + } + + defer func() { + if recover() == nil { + panic("did not panic as expected") + } + }() + // This should type check but should panic at run time, + // because it will make a slice of *SettableInt and then call + // Set on a nil value. + fromStrings3[*SettableInt]([]string{"1"}) +} |