Home > Software engineering >  Nested generic types: Reuse function's Type parameter
Nested generic types: Reuse function's Type parameter

Time:09-28

Given the following definitions:

type Collector[T, C any] interface {
    Collect(T, C) C
}

type mapCollector[K comparable, V any] struct {
    GetKey func(result V) K
}

func (m *mapCollector[K, V]) Collect(value V, c *sync.Map) *sync.Map {
    c.Store(m.GetKey(value), value)
    return c
}

I am trying to write a templated make function for mapCollector. This does not work

func MakeUserMapCollector[K UserId, V User]() *mapCollector[K, V] {
    c := mapCollector[K, V]{
        GetKey: func(user V) K {
            return user.getId()
        }
    }
    return &c
}

Instead I have to be repetitive

func MakeUserMapCollector() *mapCollector[UserId, User] {
    c := mapCollector[UserId, User]{
        GetKey: func(user User) UserId {
            return user.getId()
        }
    }
}

Is there a way to reuse the MakeUserMapCollector type parameters to declare types in the function?

CodePudding user response:

You can create a generic constructor function that accepts a function for "collection" and then passes it to your mapCollector struct.

That would look something like this:

func MakeUserMapCollector[K comparable, V any](collect func(result V) K) *mapCollector[K, V] {
    return &mapCollector[K, V]{
        GetKey: collect,
    }
}

Then you can call the constructor function with your types as type parameters and your "collection" function:

mc := MakeUserMapCollector[UserId, User](func(result User) UserId { return result.GetId() })

Full example (Go Playground):

package main

import (
    "fmt"
)

type mapCollector[K comparable, V any] struct {
    GetKey func(result V) K
}

func (m mapCollector[K, V]) Collect(result V) K {
    return m.GetKey(result)
}

type UserId string

type User struct {
    Id UserId
}

func (u User) GetId() UserId {
    return u.Id
}

func MakeUserMapCollector[K comparable, V any](collect func(result V) K) *mapCollector[K, V] {
    return &mapCollector[K, V]{
        GetKey: collect,
    }
}

func main() {
    u := User{
        Id: "12",
    }

    mc := MakeUserMapCollector[UserId, User](func(result User) UserId { return result.GetId() })
    fmt.Println(mc.Collect(u))
}
  • Related