はじめに
なんかすごいタイトル長くなってしまいましたが、タイトルのままの記事です。
「genericsを使ってみたいと思って、いざ使ったらinterfaceだけで解決できそう」と思ったら実はgenericsが有効だったという経験をしたので記事にしてみました。
どんな場面なのかで有効だったのか、サクッとみていこうと思います!
結論interfaceのsliceを使った処理に有効
サンプルコードを作ってみたので、少しみていきます!
package main
import "fmt"
type Product interface {
GetID() int
}
// ClockはProductを実装
type Clock struct {
ID int
}
func (c *Clock) GetID() int {
return c.ID
}
// TableはProductを実装
type Table struct {
ID int
}
func (t *Table) GetID() int {
return t.ID
}
// Productの重複判定処理
func isDuplicated[T Product](t []T) bool {
dupMap := map[int]struct{}{}
for _, v := range t {
if _, ok := dupMap[v.GetID()]; ok {
return true
}
dupMap[v.GetID()] = struct{}{}
}
return false
}
func main() {
if isDuplicated(clocks) {
fmt.Println("clockは重複しています")
}
if isDuplicated(tables) {
fmt.Println("tableは重複しています")
}
}
var clocks = []*Clock{
{ID: 1},
{ID: 1},
{ID: 3},
}
var tables = []*Table{
{ID: 1},
{ID: 2},
{ID: 3},
}
Productが重複しているのか判定することが目的のコードですね。
ClockとTableはどちらもProduct interfaceを実装しているので、最終的にはClockやTableが重複しているかチェックすることを目指しています。
idDuplicated関数について、genericsを用いて引数にはProductのsliceがくるようにしています。
コードは以下の部分ですね。
func isDuplicated[T Product](t []T) bool {
dupMap := map[int]struct{}{}
for _, v := range t {
if _, ok := dupMap[v.GetID()]; ok {
return true
}
dupMap[v.GetID()] = struct{}{}
}
return false
}
この部分について、
func isDuplicated(t []Product) bool
のようにInterfaceのsliceを引数の型にして、実装しても問題ないように思えます。ていうか僕は思っていました。
ただこうしてしまうと以下のようなコンパイルエラーが発生してしまいます 。
cannot use clocks (variable of type []*Clock) as type []Product in argument to isDuplicated
cannot use tables (variable of type []*Table) as type []Product in argument to isDuplicated
*Clock
や*Table
はProductを実装しているのに、sliceになると異なる型を判定されてしまいます。
genericsではこの問題を解決することができます。
func isDuplicated[T Product](t []T) bool
の部分で引数にclocks
を入れると、[]Tは[]*Clockと判定されてコンパイルしてくれるみたいですね!
<補足>
以下のようにProductのsliceにClockやTableをappendで入れていく分には問題ありません。
pros := []Product{}
pros = append(pros, &Clock{
ID: 1,
})
pros = append(pros, &Table{
ID: 1,
})
おわりに
今回はinterfaceのsliceについて、genericsを使ってうまく処理する方法を見てきました。
もしinterfaceのsliceの扱いに困っていた方がいらっしゃったらぜひこの方法も検討してみてください!
最後まで読んでいただきありがとうございました!