Source file test/typeparam/settable.go

     1  // run
     2  
     3  // Copyright 2021 The Go Authors. All rights reserved.
     4  // Use of this source code is governed by a BSD-style
     5  // license that can be found in the LICENSE file.
     6  
     7  package main
     8  
     9  import (
    10  	"fmt"
    11  	"strconv"
    12  )
    13  
    14  // Various implementations of fromStrings().
    15  
    16  type Setter[B any] interface {
    17  	Set(string)
    18  	*B
    19  }
    20  
    21  // Takes two type parameters where PT = *T
    22  func fromStrings1[T any, PT Setter[T]](s []string) []T {
    23  	result := make([]T, len(s))
    24  	for i, v := range s {
    25  		// The type of &result[i] is *T which is in the type list
    26  		// of Setter, so we can convert it to PT.
    27  		p := PT(&result[i])
    28  		// PT has a Set method.
    29  		p.Set(v)
    30  	}
    31  	return result
    32  }
    33  
    34  func fromStrings1a[T any, PT Setter[T]](s []string) []PT {
    35  	result := make([]PT, len(s))
    36  	for i, v := range s {
    37  		// The type new(T) is *T which is in the type list
    38  		// of Setter, so we can convert it to PT.
    39  		result[i] = PT(new(T))
    40  		p := result[i]
    41  		// PT has a Set method.
    42  		p.Set(v)
    43  	}
    44  	return result
    45  }
    46  
    47  // Takes one type parameter and a set function
    48  func fromStrings2[T any](s []string, set func(*T, string)) []T {
    49  	results := make([]T, len(s))
    50  	for i, v := range s {
    51  		set(&results[i], v)
    52  	}
    53  	return results
    54  }
    55  
    56  type Setter2 interface {
    57  	Set(string)
    58  }
    59  
    60  // Takes only one type parameter, but causes a panic (see below)
    61  func fromStrings3[T Setter2](s []string) []T {
    62  	results := make([]T, len(s))
    63  	for i, v := range s {
    64  		// Panics if T is a pointer type because receiver is T(nil).
    65  		results[i].Set(v)
    66  	}
    67  	return results
    68  }
    69  
    70  // Two concrete types with the appropriate Set method.
    71  
    72  type SettableInt int
    73  
    74  func (p *SettableInt) Set(s string) {
    75  	i, err := strconv.Atoi(s)
    76  	if err != nil {
    77  		panic(err)
    78  	}
    79  	*p = SettableInt(i)
    80  }
    81  
    82  type SettableString struct {
    83  	s string
    84  }
    85  
    86  func (x *SettableString) Set(s string) {
    87  	x.s = s
    88  }
    89  
    90  func main() {
    91  	s := fromStrings1[SettableInt, *SettableInt]([]string{"1"})
    92  	if len(s) != 1 || s[0] != 1 {
    93  		panic(fmt.Sprintf("got %v, want %v", s, []int{1}))
    94  	}
    95  
    96  	s2 := fromStrings1a[SettableInt, *SettableInt]([]string{"1"})
    97  	if len(s2) != 1 || *s2[0] != 1 {
    98  		x := 1
    99  		panic(fmt.Sprintf("got %v, want %v", s2, []*int{&x}))
   100  	}
   101  
   102  	// Test out constraint type inference, which should determine that the second
   103  	// type param is *SettableString.
   104  	ps := fromStrings1[SettableString]([]string{"x", "y"})
   105  	if len(ps) != 2 || ps[0] != (SettableString{"x"}) || ps[1] != (SettableString{"y"}) {
   106  		panic(s)
   107  	}
   108  
   109  	s = fromStrings2([]string{"1"}, func(p *SettableInt, s string) { p.Set(s) })
   110  	if len(s) != 1 || s[0] != 1 {
   111  		panic(fmt.Sprintf("got %v, want %v", s, []int{1}))
   112  	}
   113  
   114  	defer func() {
   115  		if recover() == nil {
   116  			panic("did not panic as expected")
   117  		}
   118  	}()
   119  	// This should type check but should panic at run time,
   120  	// because it will make a slice of *SettableInt and then call
   121  	// Set on a nil value.
   122  	fromStrings3[*SettableInt]([]string{"1"})
   123  }
   124  

View as plain text