paint-brush
Checking Palindrome With Generics in Go 1.18by@yudaph
1,355 reads
1,355 reads

Checking Palindrome With Generics in Go 1.18

by Yuda Prasetiya HaqqyApril 26th, 2022
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

This time I want to talk about my experience trying generics in Go 1.18. I’m interested in using it to create a palindrome checking function that can accept both strings and integers.
featured image - Checking Palindrome With Generics in Go 1.18
Yuda Prasetiya Haqqy HackerNoon profile picture


After reading a few articles and watching some videos about generics in Go 1.18, I got interested in using it to create a palindrome checking function that can accept both strings and integers.

First I created a new project called palindrome, and a new package (also called palindrome). Then I created constrains called signedOrString that can receive signed (int, int8, int16, int32, and int64) or a string. Further, I created a function for checking whether it is palindrome or not.

type signedOrString interface{
	constraints.Signed | string
}

func palindrome[input signedOrString](sliceInput []input) bool {
	length := len(sliceInput)
	for i:=0;i<length/2;i++{
		if sliceInput[i] != sliceInput[length-1-i] {
			return false
		}
	}
	return true
}


It’s really nice feature because we don’t have to recreate functions that do the same thing for each data type.


Then I want to upgrade the function to check palindrome directly from a word or number, not from the slice. I tried using the generics feature again and got stumbled this time because when we input type string to the function we can use the built-in Split function to convert it to slice, whereas to convert type integer to slice we need to create our own function.

How can we distinguish the flow between string and Signed (integer)?

I've come up with an idea to convert it to interface{} type, then separate the flow with switch function. Let's look at the code.


func IsPalindrome[input signedOrString](firstInput input) bool {
	return func(toInterface interface{}) bool {
		var sliceInt []int
		switch newType := toInterface.(type){
			case string:
				return palindrome(strings.Split(newType, ""))
			case int:
				sliceInt = sliceInteger(newType)
			case int8:
				sliceInt = sliceInteger(newType)
			case int16:
				sliceInt = sliceInteger(newType)
			case int32:
				sliceInt = sliceInteger(newType)
			case int64:
				sliceInt = sliceInteger(newType)
		}
		return palindrome(sliceInt)
	}(firstInput)
}

func sliceInteger[signed constraints.Signed](input signed) (slice []int) {
	for input > 0 {
		slice = append(slice, int(input%10))
		input/=10
	}
	return
}

sliceInteger function to convert any signed (integer) value to slice integer is still a good practice to use generics, but for IsPalindromefunction I think generics aren’t built to do that kind of jobs.

After that, we can call IsPalindrome function from main.go and check whether the input variable is palindrome or not.

package main

import (
	"fmt"
	"palindrome/palindrome"
)

func main() {
	fmt.Println(palindrome.IsPalindrome("AAAB")) // false
	fmt.Println(palindrome.IsPalindrome("ABABA")) // true
	fmt.Println(palindrome.IsPalindrome(10001)) // true
	fmt.Println(palindrome.IsPalindrome(10110)) // false
}

Conclusion

Go 1.18 Generics is good for building a function that has exactly same flow regardless of whatever the input type, like the palindrome and sliceIntegerfunction above.


ForIsPalindrome function - other developers who call this function have the idea that it can only be input using string or signed (integer) type.


I hope some of you find this helpful. If you’re interested in seeing all the source code, you can find it on https://github.com/yudaph/palindrome.

Thank you!


Also published here.