これは何?
go 1.18 が正式リリースになり。
以前から無くて困っていた generics がようやく入ったので、その練習
最大値関数
math.Max
が float64
しか受け入れない厳しい世界からようやく脱却。
package main
import (
"fmt"
"time"
"golang.org/x/exp/constraints"
)
func Max2[T constraints.Ordered](x, y T) T {
if x < y {
return y
}
return x
}
func main() {
fmt.Println(Max2(1, 2)) //=> 2
fmt.Println(Max2(1.11, 2.22)) //=> 2.22
fmt.Println(Max2("hoge", "fuga")) //=> hoge
fmt.Println(Max2(333*time.Millisecond, 444*time.Millisecond)) //=> 444ms
}
ここに到達するまでだいぶ時間がかかった。
constraints
は "constraints"
ではなく "golang.org/x/exp/constraints"
になった模様。
constraints.Ordered
は 比較演算子( <
とか)が使えるもの全部ということらしい。
big.Int でも Max したい
int
用と float32
用を同じ定義で書けることがはわかった。
しかし big.Int
とかもある。もちろん big.Int
を上記の Max2
に入れたらエラー。
Max2(big.NewInt(1), big.NewInt(2))
//=> *big.Int does not implement constraints.Ordered
まあそうだよね。むしろそうじゃなきゃ困る。
やりたいことは
a := Max2(1, 2)
b := Max2("hoge", "fuga")
c := Max2(big.NewInt(1), big.NewInt(2))
ができる Max2
を定義すること。
それが無理なら以下のような
x := BigMax2(big.NewInt(1), big.NewInt(2))
y := BigMax2(big.NewRat(10, 7), big.NewRat(14, 10))
z := BigMax2(big.NewFloat(1), big.NewFloat(2))
BigMax2
を定義したい。これぐらいは書けるべきと思う。
しかしまだ書けていない。
「引数の型がレシーバと同じであるメソッド Cmp
を持つ型 T
」
という制約が必要だと思うんだけど、今の所これが書けない。
難しい。
進展があったら加筆する予定。
BigMax への道(🍊未完🍊)
Generics がない場合
big.Int
だけなら、こうする。
package main
import (
"fmt"
"math/big"
)
func BigMaxInt2(x, y *big.Int) *big.Int {
if x.Cmp(y) < 0 {
return y
}
return x
}
func main() {
fmt.Println(BigMaxInt2(big.NewInt(1), big.NewInt((2))))
}
この BigMaxInt2
の型 big.Int
を引数にすればいいと思うよね。
first trial (失敗)
まずはこう書くと
type BigNumber interface {
big.Int | big.Float | big.Rat
}
func BigMax2[T BigNumber](x, y *T) *T {
// ↓ x.Cmp undefined (type *T is pointer to type parameter, not type parameter)
if x.Cmp(y) < 0 {
return y
}
return x
}
エラー。ちょっと何を言っているのかわからない。なんかわからないけどこうしてみると
type BigNumber interface {
*big.Int | *big.Float | *big.Rat
}
func BigMax2[T BigNumber](x, y T) T {
// ↓ x.Cmp undefined (type T has no field or method Cmp)
if x.Cmp(y) < 0 {
return y
}
return x
}
メッセージが変わった。
でもどうしたらいいのかわからない。