Thanks for your reply, Henry!

I admit that my problem seems a little bit silly without providing 
the contextual information. Actually I am trying to rewrite my little 
[validation library](https://github.com/RussellLuo/validating) by 
leveraging Go generics.

For the originally non-generic 
[Len](https://pkg.go.dev/github.com/RussellLuo/validating/v2#Len) validator 
factory, I have implemented two generic versions. One for a slice:

```go
// LenSlice is a leaf validator factory used to create a validator, which 
will
// succeed when the length of the slice field is between min and max.
func LenSlice[T ~[]E, E any](min, max int) (mv *MessageValidator) {
        mv = &MessageValidator{
                Message: "with an invalid length",
                Validator: Func(func(field *Field) Errors {
                        v, ok := field.Value.(T)
                        if !ok {
                                return NewUnsupportedErrors(field, 
"LenSlice")
                        }

                        l := len(v)
                        if l < min && l > max {
                                return NewErrors(field.Name, ErrInvalid, 
mv.Message)
                        }
                        return nil
                }),
        }
        return
}
```

and the other for a map:

```go
// LenMap is a leaf validator factory used to create a validator, which will
// succeed when the length of the map field is between min and max.
func LenMap[T map[K]V, K comparable, V any](min, max int) (mv 
*MessageValidator) {
        mv = &MessageValidator{
                Message: "with an invalid length",
                Validator: Func(func(field *Field) Errors {
                        v, ok := field.Value.(T)
                        if !ok {
                                return NewUnsupportedErrors(field, "LenMap")
                        }

                        l := len(v)
                        if l < min && l > max {
                                return NewErrors(field.Name, ErrInvalid, 
mv.Message)
                        }
                        return nil
                }),
        }
        return
}
```

As a result, we can use them as below:

```go
Schema{
        F("slice", []string{"foo"}): LenSlice[[]string](0, 2),
        F("map", map[string]int{"a": 1, "b": 2}): LenMap[map[string]int](0, 
2),
}
```

*Now I am wondering if I can merge the above two versions into one generic 
`Len`, with the help of a constraint, say, SliceOrMap*. For example:

```go
func Len[T SliceOrMap](min, max int) (mv *MessageValidator) {
        mv = &MessageValidator{
                Message: "with an invalid length",
                Validator: Func(func(field *Field) Errors {
                        v, ok := field.Value.(T)
                        if !ok {
                                return NewUnsupportedErrors(field, "Len")
                        }

                        l := len(v)
                        if l < min && l > max {
                                return NewErrors(field.Name, ErrInvalid, 
mv.Message)
                        }
                        return nil
                }),
        }
        return
}
```

Then we can use the same `Len` for both a slice and a map as below instead:

```go
Schema{
        F("slice", []string{"foo"}): Len[[]string](0, 2),
        F("map", map[string]int{"a": 1, "b": 2}): Len[map[string]int](0, 2),
}
```

*(NOTE*: I have posted this reply earlier, but is was not displayed (maybe 
due to my wrong choice of "Reply to author").  Now I post it again by 
selecting "Reply all".)
On Friday, March 18, 2022 at 3:07:17 PM UTC+8 Henry wrote:

> Have you considered this?
> ```go
> func IsBetween(value, min, max int) bool {
>    return value>=min && value <=max
> }
>
> if IsBetween(len(myMap), 10, 25) {
>   //do something
> }
> ```
>
> On Friday, March 18, 2022 at 11:20:37 AM UTC+7 RussellLuo wrote:
>
>> Hi there,
>>
>> Thanks to Go generics in 1.18, I can write a generic function 
>> `LenBetween` for a slice:
>>
>> ```go
>> func SliceLenBetween[T ~[]E, E any](s T, min, max int) bool {
>>         return len(s) >= min && len(s) <= max
>> }
>> ```
>>
>> as well as for a map:
>>
>> ```go
>> func MapLenBetween[T map[K]V, K comparable, V any](s T, min, max int) 
>> bool {
>>         return len(s) >= min && len(s) <= max
>> }
>> ```
>>
>> Is there any way to write a constraint, say, SliceOrMap, to support 
>> either a slice or a map?
>>
>> With the help of SliceOrMap, then I can write a more generic version 
>> `LenBetween` like this:
>>
>> ```go
>> func MapLenBetween[T SliceOrMap](s T, min, max int) bool {
>>         return len(s) >= min && len(s) <= max
>> }
>> ```
>>
>> Thanks in advance!
>>
>

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/b9790ff7-50f9-4aba-ac47-f02af7493974n%40googlegroups.com.

Reply via email to