|  | // 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"}) | 
|  | } |