2

How can I create a custom type in Go that is restricted to a certain list of string values? e.g.

type Suit = "Spade" | "Diamond" | "Club" | "Heart"
Jimmy
  • 3,090
  • 12
  • 42
  • 99

2 Answers2

7

Go does not have Algebraic data types (ADT). What you want is "sum" type in ADT. For example there are enums in Swift and Rust to support them. Go does not have generics(yet); there is no Option, Result type as well.

While what you want to do can be achieved using different ways in Go, I like using const instead of empty interface or type check or reflection. I think const would be more faster and readable. Here is how I will go. You can return the string from method instead of printing if that is what you want.

package main

import "fmt"

type Suit int

const (
    Spade Suit = iota + 1
    Diamond
    Club
    Heart
)

type Card struct {
    suit Suit
    no   int
}

func (c *Card) PrintSuit() {
    switch c.suit {
    case Spade:
        fmt.Println("Its a Spade")
    case Diamond:
        fmt.Println("Its a Diamond")
    case Club:
        fmt.Println("Its a Club")
    case Heart:
        fmt.Println("Its a Heart")
    default:
        fmt.Println("Unknown!")
    }
}

func main() {

    c := Card{suit: Diamond}

    c.PrintSuit()

}  

You can accept external func in methods like PrintSuit if the processing logic is external.

Abhijit-K
  • 3,569
  • 1
  • 23
  • 31
  • This route doesn't do anything to prevent a `Suit` value from being assigned an unwanted value (e.g. `suit = Suit(123)`), but it is perhaps the most appropriate solution for this kind of use case. – Hymns For Disco Dec 24 '20 at 06:32
  • Unwanted values are taken care in switch conditions. The important thing is suit starts from `iota + 1` instead of just iota as I want to avoid giving value 0 to any suit type because that is default case when someone does `Card{}`. Also you need to take care of proper initialization in in NewCard function that produces a right Card{}. – Abhijit-K Dec 24 '20 at 06:46
  • 1
    `This route doesn't do anything to prevent a Suit` you can consider having a non exported type with only exported values. –  Dec 24 '20 at 10:45
-2

Define a type alias for string i.e., Suit. The Suit is a type whose underlying type is a string.

Now, create some constants of type Suit. In the following ode, Spade, Diamond, Club, Heart are of type Suit. Now the function in which you want the parameter to be restricted to some input (which is not possible); but what you can do it to restrict it accept the Suit type only, and pass any of the const variable created.

// Define new type alias for string
type Suit  string

const (
    Spade Suit   = "Spade"
    Diamond Suit = "Diamond"
    Club Suit    = "Club"
    Heart Suit   = "Heart"
)

// function f only accepts parameter of type "Suit" 
func f(s Suit)  {
    fmt.Println(s)
}

func main()  {
    // Call the function f with Spade
    f(Spade)
}
Mario Petrovic
  • 7,500
  • 14
  • 42
  • 62
Mr IF
  • 9
  • 2
  • this isn't how you make data types with restricted values, also as @Abhijit_K said go doesn't suppourt it. – whitespace Dec 24 '20 at 04:03
  • 2
    this (`type Suit string`) is not a type alias, type alias has a specific syntax with specific behavior. This is a regular type declaration https://golang.org/ref/spec#Type_declarations –  Dec 24 '20 at 10:44
  • @whitespace It's already written in the answer that it's not actually possible. – shmsr Dec 24 '20 at 11:47
  • The main point is to have editor support and this just allows me to type anything into the function. I would not recommend this. – Lan Vukušič Jul 26 '22 at 14:52