0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

go generics の練習

Last updated at Posted at 2022-03-24

これは何?

go 1.18 が正式リリースになり。
以前から無くて困っていた generics がようやく入ったので、その練習

最大値関数

math.Maxfloat64 しか受け入れない厳しい世界からようやく脱却。

go1.18
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 に入れたらエラー。

go1.18
Max2(big.NewInt(1), big.NewInt(2))
//=> *big.Int does not implement constraints.Ordered

まあそうだよね。むしろそうじゃなきゃ困る。
やりたいことは

go.1.18(希望)
a := Max2(1, 2)
b := Max2("hoge", "fuga")
c := Max2(big.NewInt(1), big.NewInt(2))

ができる Max2 を定義すること。
それが無理なら以下のような

go.1.18(せめてこれぐらい)
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 だけなら、こうする。

go1.18
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 (失敗)

まずはこう書くと

go1.18
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
}

エラー。ちょっと何を言っているのかわからない。なんかわからないけどこうしてみると

go1.18
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
}

メッセージが変わった。
でもどうしたらいいのかわからない。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?