Cet article explique ce que signifie ajouter des génériques à Go, et pourquoi je pense que nous devrions le faire. J'aborderai également un éventuel changement dans l'architecture du langage afin d'ajouter des génériques.
Go est sorti le 10 novembre 2009. Moins d'un jour plus tard, le
premier commentaire sur les génériques est apparu . Il mentionne également des exceptions que nous avons ajoutées au langage sous forme de panique et que nous avons récupérées début 2010.
Pendant trois années d'observation, l'absence de génériques a toujours été une liste de trois problèmes principaux qui doivent être résolus dans la langue.
Pourquoi les génériques sont-ils nécessaires?
Que signifie l'ajout de génériques et pourquoi le voulons-nous?
Pour paraphraser
Jazayeri et d'autres : la programmation avec des génériques vous permet de représenter des fonctions et des structures de données comme des génériques, à l'exclusion des types.
Qu'est-ce que cela signifie?
Supposons que nous devons représenter les éléments de la tranche dans l'ordre inverse. Ce n'est pas une tâche très courante, mais pas si rare.
Supposons que nous ayons une tranche d'entiers.
func ReverseInts(s []int) {
first := 0
last := len(s)
for first < last {
s[first], s[last] = s[last], s[first]
first++
last--
}
}
. . , . , .
func ReverseInts(s []int) {
first := 0
last := len(s) - 1
for first < last {
s[first], s[last] = s[last], s[first]
first++
last--
}
}
1,
last
. .
func ReverseStrings(s []string) {
first := 0
last := len(s) - 1
for first < last {
s[first], s[last] = s[last], s[first]
first++
last--
}
}
ReverseInts
ReverseStrings
, , , . .
Go,
Reverse
, .
.
Python JavaScript . Go , , .
, ++, Java, Rust Swift, .
Go
Go?
, (interface type) , .
sort.Sort
.
, Go — . . , , , .
. . . , , , , , - , . — , , .
, , , - . Go , , , ,
Index
, . , , . -, , map' . Go , . .
-
Reverse
, reflect, . , .
,
Reverse
. . ,
Reverse
, - , , .
, , , Go, . , , , , . .
, , , , . , . , Go . .
Go . , . .
Go
, Go,
Reverse
. . , Go .
open source, , -
Reverse
, .
, «» . «» , . , , ++, , .
Reverse
, , , :
. , , ++.
, Go .
, . Go. , .
, . , . , , , .
Go - : map. , , . , . ,
[]int
, , , .
map' — - , . :
-, , , , map: , , , .
, , - .
,
Reverse
: - , , , . map, , , , .
Go . , .
, , .
Big Rock Candy Mountain, ,
. . , Go . , .
Go , , . , , , . .
, , .
. , .
-,, -. , . , -, - , . -.
- , . , , , . , .
Go. C . .
Go, Go . Go . . , , - .
Go. : , , Go .
, . , , Go.
Gophercon (Robert Griesemer)
Go. , .
Reverse
.
func Reverse (type Element) (s []Element) {
first := 0
last := len(s) - 1
for first < last {
s[first], s[last] = s[last], s[first]
first++
last--
}
}
, .
.
Element
(type parameter). , , , .
, , , .
func ReverseAndPrint(s []int) {
Reverse(int)(s)
fmt.Println(s)
}
(int)
,
Reverse
.
, , , , .
- .
func ReverseAndPrint(s []int) {
Reverse(s)
fmt.Println(s)
}
-
Reverse
ReverseInts
ReverseStrings
, , .
Go , .
, -, - .
Reverse
.
Element
, Go. -, , .
.
func IndexByte (type T Sequence) (s T, b byte) int {
for i := 0; i < len(s); i++ {
if s[i] == b {
return i
}
}
return -1
}
bytes strings
IndexByte
.
b
s
,
s
[]byte
. - bytes strings. , .
,
T
—
[]byte
.
len
, byte.
T
. , , - ,
T
.
Sequence
. .
Sequence
.
contract Sequence(T) {
T string, []byte
}
, :
T
[]byte
. , . .
,
, Gophercon 2018, , . , , . , .
/ . .
,
String
[]string
s
.
func ToStrings (type E Stringer) (s []E) []string {
r := make([]string, len(s))
for i, v := range s {
r[i] = v.String()
}
return r
}
: ,
String
.
,
String
.
Stringer
.
contract Stringer(T) {
T String() string
}
,
T
String
.
,
fmt.Stringer
, ,
ToStrings
fmt.Stringer
. - ,
fmt.Stringer
.
fmt.Stringer
, Go . ,
fmt.Stringer
.
.
type Graph (type Node, Edge G) struct { ... }
contract G(Node, Edge) {
Node Edges() []Edge
Edge Nodes() (from Node, to Node)
}
func New (type Node, Edge G) (nodes []Node) *Graph(Node, Edge) {
...
}
func (g *Graph(Node, Edge)) ShortestPath(from, to Node) []Edge {
...
}
, . . ,
Node
Edges
, ,
Node
.
Edge
Nodes
,
Nodes
,
Edge
.
,
New
,
Graph
,
ShortestPath
Graph
.
, - . .
(Ordered types)
Go
Min
. ,
Max
. ,
Min
, .
Min
, . :
func Min (type T Ordered) (a, b T) T {
if a < b {
return a
}
return b
}
Ordered
,
T
, « », « », .
contract Ordered(T) {
T int, int8, int16, int32, int64,
uint, uint8, uint16, uint32, uint64, uintptr,
float32, float64,
string
}
Ordered
— , . , , - . , « ».
, « », , . , Go .
, , , -, . , -, , . - , , .
, , .
Min
(, , ) .
Ordered
, .
func Min (type T contracts.Ordered) (a, b T) T {
if a < b {
return a
}
return b
}
-
, - , . , .
type Tree (type E) struct {
root *node(E)
compare func(E, E) int
}
type node (type E) struct {
val E
left, right *node(E)
}
.
New
.
func New (type E) (cmp func(E, E) int) *Tree(E) {
return &Tree(E){compare: cmp}
}
,
v
, , .
func (t *Tree(E)) find(v E) **node(E) {
pn := &t.root
for *pn != nil {
switch cmp := t.compare(v, (*pn).val); {
case cmp < 0:
pn = &(*pn).left
case cmp > 0:
pn = &(*pn).right
default:
return pn
}
}
return pn
}
, , . , - .
, .
func (t *Tree(E)) Contains(v E) bool {
return *t.find(e) != nil
}
This is the code for inserting a new value.
func (t *Tree(E)) Insert(v E) bool {
pn := t.find(v)
if *pn != nil {
return false
}
*pn = &node(E){val: v}
return true
}
E
. - . , Go, , .
.
var intTree = tree.New(func(a, b int) int { return a - b })
func InsertAndCheck(v int) {
intTree.Insert(v)
if !intTree.Contains(v) {
log.Fatalf("%d not found after insertion", v)
}
}
. - , . -- .
, . , , , . , , .
CL, go/types. , , , . , , .
, -, , . , , . , , - . , .
, , , Go. . , .
— , -, , Go. , — , , , , . , - Go.