-2

Go doesn't have array constants.

My application receives messages containing several types of numeric codes which I need to display as phrases.

If array contants existed I could do something like:

func foo() {
   ...
   fmt.Println(facename[f])
   ...
}
const facename [...]string = "top", "bottom", "left", "right", "front", "back"

But of course there's no way to do this. The first way around this that occurs to me, and maybe a reasonable efficient one is to use a switch

func foo() {
   ...
   name := "unknown"
   switch f {
   case 0:
      name = "top"
   case 1:
      name = "bottom"
   case 2:
      name = "left"
   case 3:
      name = "right"
   case 4:
      name = "front"
   case 5:
      name = "back"
   }
   fmt.Println(name)
   ...
}

The above is rather tedious if the number of values gets to be twenty or more.

It seems the most concise way is something like

func foo() {
   ...
   fmt.Println(strings.Split(facenames,",")[f])
   ...
}
const facenames = "top,bottom,left,right,front,back"

I will also have to check that the index is in range of course. Although efficiency isn't a concern at the moment, it bugs me that I'm using strings.Split() more than I want to.

Is there another way that is either idiomatic or both concise and efficient?

RedGrittyBrick
  • 3,827
  • 1
  • 30
  • 51
  • Why not use a global var instead of a constant? I mean, you don't get the "constant" protection, but as long as the variable isn't exported, only your own package could mess with it anyway. – Kaedys Jun 05 '17 at 19:12

2 Answers2

2

The idiomatic approach is to use a package level variable:

var facename = []string{"top", "bottom", "left", "right", "front", "back"}

func foo() {
    // ...
    fmt.Println(facename[f])
    // ...
}

It's also idiomatic to use a slice instead of an array in this situation.

Kaedys
  • 9,600
  • 1
  • 33
  • 40
Charlie Tumahai
  • 113,709
  • 12
  • 249
  • 242
0

It may not be a good fit, but it appears your use case is basically an enum with string equivalents. For this I usually do something along the lines of:

type Face uint8

const (
    FaceTop Face = iota
    FaceBottom
    FaceLeft
    FaceRight
    FaceFront
    FaceBack
)

func (f Face) String() string {
    switch f {
    case FaceTop: return "top"
    case FaceBottom: return "bottom"
    case FaceLeft: return "left"
    case FaceRight: return "right"
    case FaceFront: return "front"
    case FaceBack: return "back"
    default: return ""  // Or add an error return, or add a zero value to the enum
    }
}

func ParseFace(in string) (Face,error) {
    switch in {
    case "top": return FaceTop,nil
    case "bottom": return FaceBottom,nil
    case "left": return FaceLeft,nil
    case "right": return FaceRight,nil
    case "front": return FaceFront,nil
    case "back": return FaceBack,nil
    default: return "",errors.New("invalid face name"+in)
    }
}
Adrian
  • 42,911
  • 6
  • 107
  • 99
  • Incidentally, this won't compile, since the `String()` method does not have a guaranteed return value. If the given `Face` is not in the iota list (ie you manually created it, as in `var f = Face(25)`, no case will be matched, and thus String() will not have a return. The compiler blocks this, as there's a valid decision tree in which a return value is not present. – Kaedys Jun 05 '17 at 19:31
  • Also, your iotas are not of type Face in this example, so String() cannot be called on them. You need the first iota line to be `FaceTop Face = iota`. – Kaedys Jun 05 '17 at 19:32
  • Good catch on both counts - the second is from too many edits. The first is because I usually have a separate zero value for my enums I can use as a semi-valid default case, like `FaceNone` or something, so that zeroes don't equate to any "real" value, but I don't have full visibility into OP's use case. – Adrian Jun 05 '17 at 19:33
  • In most cases, I actually have the 0 iota be `Invalid`, so that a statement like `var f Face; f.String()` doesn't return valid data, and it's clear that the variable wasn't created using an iota constant. – Kaedys Jun 05 '17 at 19:35
  • The difference between 0 being called `Invalid` and `None` is down to semantics and personal preference; if having no value isn't valid, then the semantic difference disappears (none == invalid), and it's purely personal preference. – Adrian Jun 05 '17 at 19:37
  • And actually in his example `switch` he defaults to `unknown` which is another (roughly equivalent) option to None or Invalid. – Adrian Jun 05 '17 at 19:38