Search code examples
gogenerics

How to write a generic Max function


How can I write a generic max function that would take 2 values given of type string or Int or float and return a max value.


type comparable interface {
    constraints.Integer | constraints.Float
}

func max[T comparable](x, y T) T {
    return T(math.Max(float64(x), float64(y)))
}

type customComarable interface {
    comparable |  ~string
}

func Max[T customComarable](x, y T) T {
    switch v := T.(type) {
    case string:
        if len(x) > len(y) {
            return T(x)
        } else {
            return T(y)
        }
    case constraints.Integer, constraints.Float:
        return T(max(x, y))
    }
}

This how I want the generic max function but go compiler is not happy with this I'm getting an error on T.(type)

T (type) is not an expression

I clearly see, things like this Max("abc", 1) would cause problem but given that. If I know all of the consequence of writing such function and ensure proper x and y type would it be possible to do something like I mentoined above.


Solution

  • With generics it is pretty simple. Here is a more versatile function, which accepts variable number of arguments

    func Max[T constraints.Ordered](args ...T) T {
        if len(args) == 0 {
            return *new(T) // zero value of T
        }
    
        if isNan(args[0]) {
            return args[0]
        }
    
        max := args[0]
        for _, arg := range args[1:] {
    
            if isNan(arg) {
                return arg
            }
    
            if arg > max {
                max = arg
            }
        }
        return max
    }
    
    func isNan[T constraints.Ordered](arg T) bool {
        return arg != arg
    }