mirror of https://github.com/golang/go.git
[dev.go2go] cmd/go2go: in testdata, drop type keyword, always provide constraint
This is a rewrite of the tests to drop the type keyword for parameterized functions and types, and to instead always provide a constraint. We can revert if we don't like this approach. Change-Id: I9cd097b8db2aa3c84a40a7aeaa10246ab3b990dc Reviewed-on: https://go-review.googlesource.com/c/go/+/248897 Reviewed-by: Ian Lance Taylor <iant@golang.org>
This commit is contained in:
parent
bc00f5ba9f
commit
ec50ad4981
|
|
@ -8,7 +8,7 @@ package alg
|
|||
import "constraints"
|
||||
|
||||
// Max returns the maximum of two values of some ordered type.
|
||||
func Max[type T constraints.Ordered](a, b T) T {
|
||||
func Max[T constraints.Ordered](a, b T) T {
|
||||
if a < b {
|
||||
return b
|
||||
}
|
||||
|
|
@ -16,7 +16,7 @@ func Max[type T constraints.Ordered](a, b T) T {
|
|||
}
|
||||
|
||||
// Min returns the minimum of two values of some ordered type.
|
||||
func Min[type T constraints.Ordered](a, b T) T {
|
||||
func Min[T constraints.Ordered](a, b T) T {
|
||||
if a < b {
|
||||
return a
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import (
|
|||
|
||||
// ReadAll reads from c until the channel is closed or the context is
|
||||
// canceled, returning all the values read.
|
||||
func ReadAll[type Elem](ctx context.Context, c <-chan Elem) []Elem {
|
||||
func ReadAll[Elem any](ctx context.Context, c <-chan Elem) []Elem {
|
||||
var r []Elem
|
||||
for {
|
||||
select {
|
||||
|
|
@ -30,7 +30,7 @@ func ReadAll[type Elem](ctx context.Context, c <-chan Elem) []Elem {
|
|||
// Merge merges two channels into a single channel.
|
||||
// This will leave a goroutine running until either both channels are closed
|
||||
// or the context is canceled, at which point the returned channel is closed.
|
||||
func Merge[type Elem](ctx context.Context, c1, c2 <-chan Elem) <-chan Elem {
|
||||
func Merge[Elem any](ctx context.Context, c1, c2 <-chan Elem) <-chan Elem {
|
||||
r := make(chan Elem)
|
||||
go func(ctx context.Context, c1, c2 <-chan Elem, r chan<- Elem) {
|
||||
defer close(r)
|
||||
|
|
@ -60,7 +60,7 @@ func Merge[type Elem](ctx context.Context, c1, c2 <-chan Elem) <-chan Elem {
|
|||
// is sent on the returned channel. This will leave a goroutine running
|
||||
// until c is closed or the context is canceled, at which point the
|
||||
// returned channel is closed.
|
||||
func Filter[type Elem](ctx context.Context, c <-chan Elem, f func(Elem) bool) <-chan Elem {
|
||||
func Filter[Elem any](ctx context.Context, c <-chan Elem, f func(Elem) bool) <-chan Elem {
|
||||
r := make(chan Elem)
|
||||
go func(ctx context.Context, c <-chan Elem, f func(Elem) bool, r chan<- Elem) {
|
||||
defer close(r)
|
||||
|
|
@ -84,7 +84,7 @@ func Filter[type Elem](ctx context.Context, c <-chan Elem, f func(Elem) bool) <-
|
|||
// Sink returns a channel that discards all values sent to it.
|
||||
// This will leave a goroutine running until the context is canceled
|
||||
// or the returned channel is closed.
|
||||
func Sink[type Elem](ctx context.Context) chan<- Elem {
|
||||
func Sink[Elem any](ctx context.Context) chan<- Elem {
|
||||
r := make(chan Elem)
|
||||
go func(ctx context.Context, r <-chan Elem) {
|
||||
for {
|
||||
|
|
@ -103,12 +103,12 @@ func Sink[type Elem](ctx context.Context) chan<- Elem {
|
|||
|
||||
// An Exclusive is a value that may only be used by a single goroutine
|
||||
// at a time. This is implemented using channels rather than a mutex.
|
||||
type Exclusive[type Val] struct {
|
||||
type Exclusive[Val any] struct {
|
||||
c chan Val
|
||||
}
|
||||
|
||||
// MakeExclusive makes an initialized exclusive value.
|
||||
func MakeExclusive[type Val](initial Val) *Exclusive[Val] {
|
||||
func MakeExclusive[Val any](initial Val) *Exclusive[Val] {
|
||||
r := &Exclusive[Val]{
|
||||
c: make(chan Val, 1),
|
||||
}
|
||||
|
|
@ -152,7 +152,7 @@ func (e *Exclusive[Val]) Release(v Val) {
|
|||
//
|
||||
// This is a convenient way to exit a goroutine sending values when
|
||||
// the receiver stops reading them.
|
||||
func Ranger[type Elem]() (*Sender[Elem], *Receiver[Elem]) {
|
||||
func Ranger[Elem any]() (*Sender[Elem], *Receiver[Elem]) {
|
||||
c := make(chan Elem)
|
||||
d := make(chan struct{})
|
||||
s := &Sender[Elem]{
|
||||
|
|
@ -168,7 +168,7 @@ func Ranger[type Elem]() (*Sender[Elem], *Receiver[Elem]) {
|
|||
}
|
||||
|
||||
// A Sender is used to send values to a Receiver.
|
||||
type Sender[type Elem] struct {
|
||||
type Sender[Elem any] struct {
|
||||
values chan<- Elem
|
||||
done <-chan struct{}
|
||||
}
|
||||
|
|
@ -194,7 +194,7 @@ func (s *Sender[Elem]) Close() {
|
|||
}
|
||||
|
||||
// A Receiver receives values from a Sender.
|
||||
type Receiver[type Elem] struct {
|
||||
type Receiver[Elem any] struct {
|
||||
values <-chan Elem
|
||||
done chan<- struct{}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,31 +10,31 @@ import "errors"
|
|||
// A Graph is a collection of nodes. A node may have an arbitrary number
|
||||
// of edges. An edge connects two nodes. Both nodes and edges must be
|
||||
// comparable. This is an undirected simple graph.
|
||||
type Graph[type Node NodeC[Edge], Edge EdgeC[Node]] struct {
|
||||
type Graph[Node NodeC[Edge], Edge EdgeC[Node]] struct {
|
||||
nodes []Node
|
||||
}
|
||||
|
||||
// NodeC is the contraints on a node in a graph, given the Edge type.
|
||||
type NodeC[type Edge] interface {
|
||||
type NodeC[Edge any] interface {
|
||||
comparable
|
||||
Edges() []Edge
|
||||
}
|
||||
|
||||
// Edgec is the constraints on an edge in a graph, given the Node type.
|
||||
type EdgeC[type Node] interface {
|
||||
type EdgeC[Node any] interface {
|
||||
comparable
|
||||
Nodes() (a, b Node)
|
||||
}
|
||||
|
||||
// New creates a new Graph from a collection of Nodes.
|
||||
func New[type Node NodeC[Edge], Edge EdgeC[Node]](nodes []Node) *Graph[Node, Edge] {
|
||||
func New[Node NodeC[Edge], Edge EdgeC[Node]](nodes []Node) *Graph[Node, Edge] {
|
||||
return &Graph[Node, Edge]{nodes: nodes}
|
||||
}
|
||||
|
||||
// nodePath holds the path to a node during ShortestPath.
|
||||
// This should ideally be a type defined inside ShortestPath,
|
||||
// but the translator tool doesn't support that.
|
||||
type nodePath[type Node NodeC[Edge], Edge EdgeC[Node]] struct {
|
||||
type nodePath[Node NodeC[Edge], Edge EdgeC[Node]] struct {
|
||||
node Node
|
||||
path []Edge
|
||||
}
|
||||
|
|
@ -79,12 +79,12 @@ type GraphP[type *Node NodeCP[Edge], *Edge EdgeCP[Node]] struct {
|
|||
}
|
||||
|
||||
// NodeCP is the contraint on a Node in a GraphP.
|
||||
type NodeCP[type Edge] interface {
|
||||
type NodeCP[Edge any] interface {
|
||||
Edges() []*Edge
|
||||
}
|
||||
|
||||
// EdgeCP is the contraint on an Edge in a GraphP.
|
||||
type EdgeCP[type Node] interface {
|
||||
type EdgeCP[Node any] interface {
|
||||
Nodes() (a, b *Node)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import (
|
|||
)
|
||||
|
||||
// orderedSlice is a slice of values of some ordered type.
|
||||
type orderedSlice[type Elem constraints.Ordered] []Elem
|
||||
type orderedSlice[Elem constraints.Ordered] []Elem
|
||||
|
||||
// orderedSlice implements sort.Interface.
|
||||
|
||||
|
|
@ -30,13 +30,13 @@ func (s orderedSlice[Elem]) Less(i, j int) bool {
|
|||
func (s orderedSlice[Elem]) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||
|
||||
// OrderedSlice sorts a slice of any ordered type in ascending order.
|
||||
func OrderedSlice[type Elem constraints.Ordered](s []Elem) {
|
||||
func OrderedSlice[Elem constraints.Ordered](s []Elem) {
|
||||
sort.Sort(orderedSlice[Elem](s))
|
||||
}
|
||||
|
||||
// sliceFn implements sort.Interface for a slice of any type with an
|
||||
// explicit less-than function.
|
||||
type sliceFn[type Elem] struct {
|
||||
type sliceFn[Elem any] struct {
|
||||
s []Elem
|
||||
less func(Elem, Elem) bool
|
||||
}
|
||||
|
|
@ -46,6 +46,6 @@ func (s sliceFn[Elem]) Less(i, j int) bool { return s.less(s.s[i], s.s[j]) }
|
|||
func (s sliceFn[Elem]) Swap(i, j int) { s.s[i], s.s[j] = s.s[j], s.s[i] }
|
||||
|
||||
// SliceFn sorts a slice of any type according to a less-than function.
|
||||
func SliceFn[type Elem](s []Elem, less func(Elem, Elem) bool) {
|
||||
func SliceFn[Elem any](s []Elem, less func(Elem, Elem) bool) {
|
||||
sort.Sort(sliceFn[Elem]{s, less})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ func TestSortOrderedStrings(t *testing.T) {
|
|||
testOrdered(t, strs, sort.Strings)
|
||||
}
|
||||
|
||||
func testOrdered[type Elem constraints.Ordered](t *testing.T, s []Elem, sorter func([]Elem)) {
|
||||
func testOrdered[Elem constraints.Ordered](t *testing.T, s []Elem, sorter func([]Elem)) {
|
||||
s1 := make([]Elem, len(s))
|
||||
copy(s1, s)
|
||||
s2 := make([]Elem, len(s))
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ package list
|
|||
// perhaps with different type names.
|
||||
|
||||
// Element is an element of a linked list.
|
||||
type Element[type TElem] struct {
|
||||
type Element[TElem any] struct {
|
||||
// Next and previous pointers in the doubly-linked list of elements.
|
||||
// To simplify the implementation, internally a list l is implemented
|
||||
// as a ring, such that &l.root is both the next element of the last
|
||||
|
|
@ -42,7 +42,7 @@ func (e *Element[TElem]) Prev() *Element[TElem] {
|
|||
|
||||
// List represents a doubly linked list.
|
||||
// The zero value for List is an empty list ready to use.
|
||||
type List[type TElem] struct {
|
||||
type List[TElem any] struct {
|
||||
root Element[TElem] // sentinel list element, only &root, root.prev, and root.next are used
|
||||
len int // current list length excluding (this) sentinel element
|
||||
}
|
||||
|
|
@ -56,7 +56,7 @@ func (l *List[TElem]) Init() *List[TElem] {
|
|||
}
|
||||
|
||||
// New returns an initialized list.
|
||||
func New[type TElem]() *List[TElem] { return new(List[TElem]).Init() }
|
||||
func New[TElem any]() *List[TElem] { return new(List[TElem]).Init() }
|
||||
|
||||
// Len returns the number of elements of list l.
|
||||
// The complexity is O(1).
|
||||
|
|
@ -235,7 +235,7 @@ func (l *List[TElem]) PushFrontList(other *List[TElem]) {
|
|||
}
|
||||
|
||||
// Transform runs a transform function on a list returning a new list.
|
||||
func Transform[type TElem1, TElem2](lst *List[TElem1], f func(TElem1) TElem2) *List[TElem2] {
|
||||
func Transform[TElem1, TElem2 any](lst *List[TElem1], f func(TElem1) TElem2) *List[TElem2] {
|
||||
ret := New[TElem2]()
|
||||
for p := lst.Front(); p != nil; p = p.Next() {
|
||||
ret.PushBack(f(p.Value))
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import (
|
|||
"testing"
|
||||
)
|
||||
|
||||
func checkListLen[type TElem](t *testing.T, l *List[TElem], len int) bool {
|
||||
func checkListLen[TElem any](t *testing.T, l *List[TElem], len int) bool {
|
||||
if n := l.Len(); n != len {
|
||||
t.Errorf("l.Len() = %d, want %d", n, len)
|
||||
return false
|
||||
|
|
@ -17,7 +17,7 @@ func checkListLen[type TElem](t *testing.T, l *List[TElem], len int) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
func checkListPointers[type TElem](t *testing.T, l *List[TElem], es []*Element[TElem]) {
|
||||
func checkListPointers[TElem any](t *testing.T, l *List[TElem], es []*Element[TElem]) {
|
||||
root := &l.root
|
||||
|
||||
if !checkListLen(t, l, len(es)) {
|
||||
|
|
@ -143,7 +143,7 @@ func TestList(t *testing.T) {
|
|||
checkListPointers(t, l2, []*(Element[int]){})
|
||||
}
|
||||
|
||||
func checkList[type TElem comparable](t *testing.T, l *List[TElem], es []interface{}) {
|
||||
func checkList[TElem comparable](t *testing.T, l *List[TElem], es []interface{}) {
|
||||
if !checkListLen(t, l, len(es)) {
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,12 +5,9 @@
|
|||
// Package maps implements simple functions to manipulate maps in various ways.
|
||||
package maps
|
||||
|
||||
// any is a convenient type bound.
|
||||
type any interface{}
|
||||
|
||||
// Keys returns the keys of the map m.
|
||||
// The keys will be an indeterminate order.
|
||||
func Keys[type K comparable, V any](m map[K]V) []K {
|
||||
func Keys[K comparable, V any](m map[K]V) []K {
|
||||
r := make([]K, 0, len(m))
|
||||
for k := range m {
|
||||
r = append(r, k)
|
||||
|
|
@ -20,7 +17,7 @@ func Keys[type K comparable, V any](m map[K]V) []K {
|
|||
|
||||
// Values returns the values of the map m.
|
||||
// The values will be in an indeterminate order.
|
||||
func Values[type K comparable, V any](m map[K]V) []V {
|
||||
func Values[K comparable, V any](m map[K]V) []V {
|
||||
r := make([]V, 0, len(m))
|
||||
for _, v := range m {
|
||||
r = append(r, v)
|
||||
|
|
@ -30,7 +27,7 @@ func Values[type K comparable, V any](m map[K]V) []V {
|
|||
|
||||
// Equal reports whether two maps contain the same key/value pairs.
|
||||
// Values are compared using ==.
|
||||
func Equal[type K, V comparable](m1, m2 map[K]V) bool {
|
||||
func Equal[K, V comparable](m1, m2 map[K]V) bool {
|
||||
if len(m1) != len(m2) {
|
||||
return false
|
||||
}
|
||||
|
|
@ -43,7 +40,7 @@ func Equal[type K, V comparable](m1, m2 map[K]V) bool {
|
|||
}
|
||||
|
||||
// Copy returns a copy of m.
|
||||
func Copy[type K comparable, V any](m map[K]V) map[K]V {
|
||||
func Copy[K comparable, V any](m map[K]V) map[K]V {
|
||||
r := make(map[K]V, len(m))
|
||||
for k, v := range m {
|
||||
r[k] = v
|
||||
|
|
@ -53,7 +50,7 @@ func Copy[type K comparable, V any](m map[K]V) map[K]V {
|
|||
|
||||
// Add adds all key/value pairs in m2 to m1. Keys in m2 that are already
|
||||
// present in m1 will be overwritten with the value in m2.
|
||||
func Add[type K comparable, V any](m1, m2 map[K]V) {
|
||||
func Add[K comparable, V any](m1, m2 map[K]V) {
|
||||
for k, v := range m2 {
|
||||
m1[k] = v
|
||||
}
|
||||
|
|
@ -61,7 +58,7 @@ func Add[type K comparable, V any](m1, m2 map[K]V) {
|
|||
|
||||
// Sub removes all keys in m2 from m1. Keys in m2 that are not present
|
||||
// in m1 are ignored. The values in m2 are ignored.
|
||||
func Sub[type K comparable, V any](m1, m2 map[K]V) {
|
||||
func Sub[K comparable, V any](m1, m2 map[K]V) {
|
||||
for k := range m2 {
|
||||
delete(m1, k)
|
||||
}
|
||||
|
|
@ -69,7 +66,7 @@ func Sub[type K comparable, V any](m1, m2 map[K]V) {
|
|||
|
||||
// Intersect removes all keys from m1 that are not present in m2.
|
||||
// Keys in m2 that are not in m1 are ignored. The values in m2 are ignored.
|
||||
func Intersect[type K comparable, V any](m1, m2 map[K]V) {
|
||||
func Intersect[K comparable, V any](m1, m2 map[K]V) {
|
||||
for k := range m1 {
|
||||
if _, ok := m2[k]; !ok {
|
||||
delete(m1, k)
|
||||
|
|
@ -78,7 +75,7 @@ func Intersect[type K comparable, V any](m1, m2 map[K]V) {
|
|||
}
|
||||
|
||||
// Filter deletes any key/value pairs from m for which f returns false.
|
||||
func Filter[type K comparable, V any](m map[K]V, f func(K, V) bool) {
|
||||
func Filter[K comparable, V any](m map[K]V, f func(K, V) bool) {
|
||||
for k, v := range m {
|
||||
if !f(k, v) {
|
||||
delete(m, k)
|
||||
|
|
@ -87,7 +84,7 @@ func Filter[type K comparable, V any](m map[K]V, f func(K, V) bool) {
|
|||
}
|
||||
|
||||
// TransformValues applies f to each value in m. The keys remain unchanged.
|
||||
func TransformValues[type K comparable, V any](m map[K]V, f func(V) V) {
|
||||
func TransformValues[K comparable, V any](m map[K]V, f func(V) V) {
|
||||
for k, v := range m {
|
||||
m[k] = f(v)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import (
|
|||
)
|
||||
|
||||
// Metric1 tracks metrics of values of some type.
|
||||
type Metric1[type T comparable] struct {
|
||||
type Metric1[T comparable] struct {
|
||||
mu sync.Mutex
|
||||
m map[T]int
|
||||
}
|
||||
|
|
@ -40,13 +40,13 @@ func (m *Metric1[T]) Metrics() []T {
|
|||
return maps.Keys(m.m)
|
||||
}
|
||||
|
||||
type key2[type T1, T2 comparable] struct {
|
||||
type key2[T1, T2 comparable] struct {
|
||||
f1 T1
|
||||
f2 T2
|
||||
}
|
||||
|
||||
// Metric2 tracks metrics of pairs of values.
|
||||
type Metric2[type T1, T2 comparable] struct {
|
||||
type Metric2[T1, T2 comparable] struct {
|
||||
mu sync.Mutex
|
||||
m map[key2[T1, T2]]int
|
||||
}
|
||||
|
|
@ -77,14 +77,14 @@ func (m *Metric2[T1, T2]) Metrics() (r1 []T1, r2 []T2) {
|
|||
return r1, r2
|
||||
}
|
||||
|
||||
type key3[type T1, T2, T3 comparable] struct {
|
||||
type key3[T1, T2, T3 comparable] struct {
|
||||
f1 T1
|
||||
f2 T2
|
||||
f3 T3
|
||||
}
|
||||
|
||||
// Metric3 tracks metrics of triplets of values.
|
||||
type Metric3[type T1, T2, T3 comparable] struct {
|
||||
type Metric3[T1, T2, T3 comparable] struct {
|
||||
mu sync.Mutex
|
||||
m map[key3[T1, T2, T3]]int
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,13 +15,13 @@ import (
|
|||
)
|
||||
|
||||
// Map is an ordered map.
|
||||
type Map[type K, V] struct {
|
||||
type Map[K, V any] struct {
|
||||
root *node[K, V]
|
||||
compare func(K, K) int
|
||||
}
|
||||
|
||||
// node is the type of a node in the binary tree.
|
||||
type node[type K, V] struct {
|
||||
type node[K, V any] struct {
|
||||
key K
|
||||
val V
|
||||
left, right *node[K, V]
|
||||
|
|
@ -30,14 +30,14 @@ type node[type K, V] struct {
|
|||
// New returns a new map. It takes a comparison function that compares two
|
||||
// keys and returns < 0 if the first is less, == 0 if they are equal,
|
||||
// > 0 if the first is greater.
|
||||
func New[type K, V](compare func(K, K) int) *Map[K, V] {
|
||||
func New[K, V any](compare func(K, K) int) *Map[K, V] {
|
||||
return &Map[K, V]{compare: compare}
|
||||
}
|
||||
|
||||
// NewOrdered returns a new map whose key is an ordered type.
|
||||
// This is like New, but does not require providing a compare function.
|
||||
// The map compare function uses the obvious key ordering.
|
||||
func NewOrdered[type K constraints.Ordered, V interface{}]() *Map[K, V] {
|
||||
func NewOrdered[K constraints.Ordered, V any]() *Map[K, V] {
|
||||
return New[K, V](func(k1, k2 K) int {
|
||||
switch {
|
||||
case k1 < k2:
|
||||
|
|
@ -92,7 +92,7 @@ func (m *Map[K, V]) Find(key K) (V, bool) {
|
|||
}
|
||||
|
||||
// keyValue is a pair of key and value used while iterating.
|
||||
type keyValue[type K, V] struct {
|
||||
type keyValue[K, V any] struct {
|
||||
key K
|
||||
val V
|
||||
}
|
||||
|
|
@ -119,7 +119,7 @@ func (m *Map[K, V]) Iterate() *Iterator[K, V] {
|
|||
}
|
||||
|
||||
// Iterator is used to iterate over the map.
|
||||
type Iterator[type K, V] struct {
|
||||
type Iterator[K, V any] struct {
|
||||
r *chans.Receiver[keyValue[K, V]]
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,12 +6,12 @@
|
|||
package sets
|
||||
|
||||
// A Set is a set of elements of some type.
|
||||
type Set[type Elem comparable] struct {
|
||||
type Set[Elem comparable] struct {
|
||||
m map[Elem]struct{}
|
||||
}
|
||||
|
||||
// Make makes a new set.
|
||||
func Make[type Elem comparable]() Set[Elem] {
|
||||
func Make[Elem comparable]() Set[Elem] {
|
||||
return Set[Elem]{m: make(map[Elem]struct{})}
|
||||
}
|
||||
|
||||
|
|
@ -48,7 +48,7 @@ func (s Set[Elem]) Values() []Elem {
|
|||
}
|
||||
|
||||
// Equal reports whether two sets contain the same elements.
|
||||
func Equal[type Elem comparable](s1, s2 Set[Elem]) bool {
|
||||
func Equal[Elem comparable](s1, s2 Set[Elem]) bool {
|
||||
if len(s1.m) != len(s2.m) {
|
||||
return false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import (
|
|||
|
||||
// Equal reports whether two slices are equal: the same length and all
|
||||
// elements equal. All floating point NaNs are considered equal.
|
||||
func Equal[type Elem comparable](s1, s2 []Elem) bool {
|
||||
func Equal[Elem comparable](s1, s2 []Elem) bool {
|
||||
if len(s1) != len(s2) {
|
||||
return false
|
||||
}
|
||||
|
|
@ -31,7 +31,7 @@ func Equal[type Elem comparable](s1, s2 []Elem) bool {
|
|||
|
||||
// EqualFn reports whether two slices are equal using a comparision
|
||||
// function on each element.
|
||||
func EqualFn[type Elem](s1, s2 []Elem, eq func(Elem, Elem) bool) bool {
|
||||
func EqualFn[Elem any](s1, s2 []Elem, eq func(Elem, Elem) bool) bool {
|
||||
if len(s1) != len(s2) {
|
||||
return false
|
||||
}
|
||||
|
|
@ -45,7 +45,7 @@ func EqualFn[type Elem](s1, s2 []Elem, eq func(Elem, Elem) bool) bool {
|
|||
}
|
||||
|
||||
// Map turns a []Elem1 to a []Elem2 using a mapping function.
|
||||
func Map[type Elem1, Elem2](s []Elem1, f func(Elem1) Elem2) []Elem2 {
|
||||
func Map[Elem1, Elem2 any](s []Elem1, f func(Elem1) Elem2) []Elem2 {
|
||||
r := make([]Elem2, len(s))
|
||||
for i, v := range s {
|
||||
r[i] = f(v)
|
||||
|
|
@ -55,7 +55,7 @@ func Map[type Elem1, Elem2](s []Elem1, f func(Elem1) Elem2) []Elem2 {
|
|||
|
||||
// Reduce reduces a []Elem1 to a single value of type Elem2 using
|
||||
// a reduction function.
|
||||
func Reduce[type Elem1, Elem2](s []Elem1, initializer Elem2, f func(Elem2, Elem1) Elem2) Elem2 {
|
||||
func Reduce[Elem1, Elem2 any](s []Elem1, initializer Elem2, f func(Elem2, Elem1) Elem2) Elem2 {
|
||||
r := initializer
|
||||
for _, v := range s {
|
||||
r = f(r, v)
|
||||
|
|
@ -64,7 +64,7 @@ func Reduce[type Elem1, Elem2](s []Elem1, initializer Elem2, f func(Elem2, Elem1
|
|||
}
|
||||
|
||||
// Filter filters values from a slice using a filter function.
|
||||
func Filter[type Elem](s []Elem, f func(Elem) bool) []Elem {
|
||||
func Filter[Elem any](s []Elem, f func(Elem) bool) []Elem {
|
||||
var r []Elem
|
||||
for _, v := range s {
|
||||
if f(v) {
|
||||
|
|
@ -76,7 +76,7 @@ func Filter[type Elem](s []Elem, f func(Elem) bool) []Elem {
|
|||
|
||||
// Max returns the maximum element in a slice of some ordered type.
|
||||
// If the slice is empty it returns the zero value of the element type.
|
||||
func Max[type Elem constraints.Ordered](s []Elem) Elem {
|
||||
func Max[Elem constraints.Ordered](s []Elem) Elem {
|
||||
if len(s) == 0 {
|
||||
var zero Elem
|
||||
return zero
|
||||
|
|
@ -86,7 +86,7 @@ func Max[type Elem constraints.Ordered](s []Elem) Elem {
|
|||
|
||||
// Min returns the minimum element in a slice of some ordered type.
|
||||
// If the slice is empty it returns the zero value of the element type.
|
||||
func Min[type Elem constraints.Ordered](s []Elem) Elem {
|
||||
func Min[Elem constraints.Ordered](s []Elem) Elem {
|
||||
if len(s) == 0 {
|
||||
var zero Elem
|
||||
return zero
|
||||
|
|
@ -99,7 +99,7 @@ func Min[type Elem constraints.Ordered](s []Elem) Elem {
|
|||
// of how to write it using generics. We used to write code like
|
||||
// this before append was added to the language, but we had to write
|
||||
// a separate copy for each type.
|
||||
func Append[type T](s []T, t ...T) []T {
|
||||
func Append[T any](s []T, t ...T) []T {
|
||||
lens := len(s)
|
||||
tot := lens + len(t)
|
||||
if tot <= cap(s) {
|
||||
|
|
@ -116,7 +116,7 @@ func Append[type T](s []T, t ...T) []T {
|
|||
// Copy copies values from t to s, stopping when either slice is full,
|
||||
// returning the number of values copied. This is like the predeclared
|
||||
// copy function; it's an example of how to write it using generics.
|
||||
func Copy[type T](s, t []T) int {
|
||||
func Copy[T any](s, t []T) int {
|
||||
i := 0
|
||||
for ; i < len(s) && i < len(t); i++ {
|
||||
s[i] = t[i]
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ func TestEqual(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func offByOne[type Elem constraints.Integer](a, b Elem) bool {
|
||||
func offByOne[Elem constraints.Integer](a, b Elem) bool {
|
||||
return a == b + 1 || a == b - 1
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue