-4

I have this string to create with a Sprintf

message := fmt.Sprintf("Unit %s has a Level of %v, but is of Category %v",
    *entity.Name, *entity.LevelCode, *entity.CategoryCode)

In entity, the variables are pointers that can be nil:

  • Name is a *string
  • LevelCode has a *LevelCode type
  • CategoryCode has a *CategoryCode type

but if they have a value, I want this value and not the pointers. (i.e. Unit ABC has a Level of nil, but is of Category AdministrativeUnit)

in any language, I would have wrote:

message := fmt.Sprintf("Unit %s has a Level of %v, but is of %v Category",
    entity.Name != nil ? *entity.Name : "nil", entity.LevelCode != nil ? *entity.LevelCode : "nil", entity.CategoryCode != nil ? *entity.CategoryCode : "nil")

But Go doesn't allow ternary operator. And if I don't take care of nil values, Sprintf will throw an exception.

So, do I have to start that way?

if entity.Name == nil && entity.LevelCode != nil && entity.CategoryCode != nil) {
   message := "Unit nil has a Level of nil, but is of nil Category"
}
else {
   if entity.Name != nil && entity.LevelCode != nil && entity.CategoryCode != nil) {
     message := fmt.Sprintf("Unit %s has a Level of nil, but is of nil Category",
    entity.Name != nil ? *entity.Name : "nil")
   }
   else {
      ...

     for 9 combinations of values nil or not nil values, and 9 sprintf formats?
   }
}

What the shortest way to dump my variables content in a formatted line?
Marc Le Bihan
  • 2,308
  • 2
  • 23
  • 41
  • 2
    Use a function with an `if ... else` instead of the ternary operator? – isaactfa Jun 29 '23 at 12:28
  • 3
    Write a small wrapper `s := func(ps *string)string{if ps==nil{return ""}retunr *ps}`. – Volker Jun 29 '23 at 12:29
  • @Volker it's 5 statements put in the same line for a single type among the three I have to treat. It would to 15 lines or statements at the end. – Marc Le Bihan Jun 29 '23 at 12:30
  • @isaactfa function declaration with any pointer (if possible) could work. Calling this function three time then in the sprintf function. Ok. The cost for sprinf would be to write in in four statements instead of one like in all other languages, but it's already a great improvement for me, a good workaround to this Golang design flaw. Thanks! – Marc Le Bihan Jun 29 '23 at 12:34
  • 3
    No, you missunderstood. You write that function closure _once_. Yes that is 8 lines. If you cannot bear writing 8 lines there is no solution available except switching languages. Then _use_ that function in the Printf call like `fmt.Sprintf("%s %s %s", s(entity.Name), s(entity.LevelCode) , ... )`hope you get it. – Volker Jun 29 '23 at 13:35
  • Does this answer your question? [What is the idiomatic Go equivalent of C's ternary operator?](https://stackoverflow.com/questions/19979178/what-is-the-idiomatic-go-equivalent-of-cs-ternary-operator) – Karl Knechtel Jun 30 '23 at 14:18
  • 2
    Another possibility, that would allow to use _any_ Sprintf or similar without any wrapper is to implement the Stringer interface for the 3 types Name, LevelCode and CategoryCode. I would have posted the answer but the question is closed, so I added it to the playground: https://go.dev/play/p/Dhp_icy-way – marco.m Jun 30 '23 at 19:05

1 Answers1

-3

Thanks, with your help, I succeed in building the function.

// value treat pointers that can be nil, and return their values if they aren't.
func value[T any](v *T) string {
    if (v != nil) {
        return fmt.Sprintf("%v", *v)
    } else {
        return "nil"
    }
}

Called that way

message := fmt.Sprintf("Unit %s has a Level of %v, but is of %v Category",
    value(entity.Name), value(entity.LevelCode), value(entity.CategoryCode))

Five statements to write for single Sprintf... But it works.

Marc Le Bihan
  • 2,308
  • 2
  • 23
  • 41