Skip to content

Instantly share code, notes, and snippets.

@devlights
Last active February 20, 2022 06:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save devlights/a61067a038735fe0d6447efffb5ea7c1 to your computer and use it in GitHub Desktop.
Save devlights/a61067a038735fe0d6447efffb5ea7c1 to your computer and use it in GitHub Desktop.
Go1.18 Generic examples
package main
import "fmt"
// https://go.dev/doc/tutorial/generics
func main() {
var (
ints = []int64{1, 2, 3, 4, 5}
floats = []float64{1.1, 1.2, 1.3, 1.4, 1.5}
)
// Use non generic functions
var (
r1 = sumInts(ints...)
r2 = sumFloats(floats...)
)
fmt.Println(r1, r2)
// Use generic function
//
// どちらの型の値もサポートするためには、その関数がどの型をサポートするかを宣言する方法が必要です。
// 一方、呼び出し側のコードは、整数マップと浮動小数点マップのどちらを呼び出すかを指定する方法が必要です。
//
// これをサポートするために、通常の関数パラメータに加えて、型パラメータを宣言した関数を書くことになります。
// この型パラメータは、関数を汎用的なものにし、異なる型の引数を扱えるようにします。
// この関数を、型引数と通常の関数引数で呼び出します。
//
// 各型パラメタには,型パラメタのメタ型のような役割を果たす型制約があります。
// それぞれの型制約は、呼び出し元のコードがそれぞれの型パラメータに使用できる許容される型引数を指定します。
//
// 型パラメータの制約は通常、一連の型を表しますが、コンパイル時には、型パラメータは単一の型、
// つまり呼び出し元のコードで型引数として提供される型を表します。
// 型引数の型が型パラメータの制約で許可されていない場合、そのコードはコンパイルされません。
//
// 型パラメータは、ジェネリックコードが実行するすべての操作をサポートしなければならないことに留意してください。
// 例えば、関数のコードが、制約に数値型が含まれる型パラメータに対して
// 文字列操作(インデックス作成など)を行おうとすると、そのコードはコンパイルされません。
//
// Goコンパイラが型を推論できる場合は、呼び出しコードで型引数を省略することができます。
// コンパイラは関数の引数の型から型引数を推論します。
var (
r3 = sum[int64](ints...)
r4 = sum(floats...)
)
fmt.Println(r3, r4)
}
func sumInts(items ...int64) int64 {
var (
total int64
)
for _, v := range items {
total += v
}
return total
}
func sumFloats(items ...float64) float64 {
var (
total float64
)
for _, v := range items {
total += v
}
return total
}
// sum -- A generic type function.
//
// V型パラメータに、int64とfloat64の2つの型の和である制約を指定します。
// |を使用すると、2つの型の和集合を指定し、この制約がどちらの型も許可することを意味します。
// どちらの型も、呼び出し側コードの引数としてコンパイラによって許可されます。
func sum[V int64 | float64](items ...V) V {
var (
total V
)
for _, v := range items {
total += v
}
return total
}
package main
import "fmt"
type (
// Type constraint
// 制約を独自のインターフェースに移動し、複数の場所で再利用できるように出来ます。
// このように制約を宣言することで、制約がより複雑になった場合など、コードの効率化に役立ちます。
//
// 型制約をインターフェースとして宣言します。
// この制約は、そのインタフェースを実装する任意の型を許容します。
// 例えば、3つのメソッドを持つ型制約インタフェースを宣言し、
// それをジェネリック関数の型引数で使用する場合、
// 関数を呼び出すために使用される型引数はこれらのメソッドを
// すべて持っていなければなりません。
Number interface {
int64 | float64
}
)
// https://go.dev/doc/tutorial/generics
func main() {
var (
ints = []int64{1, 2, 3, 4, 5}
floats = []float64{1.1, 1.2, 1.3, 1.4, 1.5}
)
var (
r1 = sum(ints...)
r2 = sum(floats...)
)
fmt.Println(r1, r2)
}
func sum[V Number](items ...V) V {
var (
total V
)
for _, v := range items {
total += v
}
return total
}
package main
import "fmt"
type (
mapkey struct {
id int
name string
}
mapvalue string
)
// https://go.dev/doc/tutorial/generics
func main() {
var (
m = map[mapkey]mapvalue{
mapkey{1, "name1"}: mapvalue("hello"),
mapkey{2, "name2"}: mapvalue("world"),
}
)
// Compile Error
// ./main.go:21:7: string is not an interface
//show1(m)
// OK
show2(m)
}
func show1[K comparable, V string](m map[K]V) {
for k, v := range m {
fmt.Println(k, v)
}
}
func show2[K comparable, V ~string](m map[K]V) {
for k, v := range m {
fmt.Println(k, v)
}
}
package main
import "fmt"
type (
request struct {
host *string
port *int
}
)
func p(r request) {
if r.host != nil {
fmt.Println(*r.host)
}
if r.port != nil {
fmt.Println(*r.port)
}
}
// ptrInt returns *int (non-generic function)
func ptrInt(i int) *int {
return &i
}
// ptrStr returns *string (non-generic function)
func ptrStr(s string) *string {
return &s
}
// ptr returns *T (generic function)
func ptr[T any](t T) *T {
return &t
}
// main is a entry point function of this app.
//
// REFERENCES:
// - https://github.com/akutz/go-generics-the-hard-way/blob/main/01-prereqs
// - https://github.com/akutz/go-generics-the-hard-way/blob/main/02-hello-world
func main() {
p(request{
//host: ptrStr("0.0.0.0"),
host: ptr("0.0.0.0"),
//port: ptrInt(3333),
port: ptr(3333),
})
}
package main
import "fmt"
type (
// Constraints
numeric interface {
int | int8 | int32 | int64
}
)
// main is the entry point of this application.
//
// REFERENCES:
// - https://github.com/akutz/go-generics-the-hard-way/blob/main/03-getting-started/03-constraints.md
func main() {
var (
ints1 = []int{1, 2, 3}
ints2 = []int64{1,2,3}
ints3 = []int8{1,2,3}
)
fmt.Println(sum(ints1...))
fmt.Println(sum(ints2...))
fmt.Println(sum(ints3...))
}
func sum[T numeric](items ...T) T {
var (
total T
)
for _, v := range items {
total += v
}
return total
}
@devlights
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment