views:

184

answers:

4

I'm used to Java's String where we can pass null rather than "" for special meanings, such as use a default value.

In Go, string is a primitive type, so I cannot pass nil (null) to a parameter that requires a string.

I could write the function using pointer type, like this:

func f(s *string)

so caller can call that function either as

f(nil)

or

// not so elegant
temp := "hello";
f(&temp)

but the following is unfortunately not allowed:

// elegant but disallowed
f(&"hello");

What is the best way to have a parameter that receives either a string or nil?

A: 

I have to qualify this with the fact that I haven't actually been able to play with Go yet, I've just been reading docs for the last few days. Thus, I can't actually test the following code.

If you bind string to a new type, i.e. MyString, can you use nil then, as in the following?

type MyString string

func f(s MyString) { if s == nil { /*use default*/ } }

Or you could wrap the string in a struct. Annoying, granted, and not elegant in practice, but it's another work around.

Bill Ayakatubby
Thanks for the idea, I tried it, but it doesn't work. nil is not allowed to be passed as MyString.
yuku
A: 

Not realy attend answer : but warping value in a structure can provide some generic utility methode. (Haskell Maybe ?)

//#maybe.go
package maybe

import "log"

type MayHaveValue struct {
 IsValue bool;
}

func (this MayHaveValue) IsJust() bool {
 return this.IsValue
}

type AString struct {
 MayHaveValue;
 Value string;
}

func String(aString string) AString {
 return AString{MayHaveValue{true}, aString}
}

var NoString AString = AString{MayHaveValue{false}, ""}

func (this AString) String() (value string) {
 if this.IsJust() == true {
  value = this.Value;
 } else {
  log.Crash("Access to non existent maybeString value");
 }
 return;
}

func (this AString) OrDefault(defaultString string) (value string) {
 if this.IsJust() {
  value = this.Value;
 } else {
  value = defaultString;
 }
 return;
}

//#main.go
package main

import "fmt"
import "maybe"

func say(canBeString maybe.AString) {
 if canBeString.IsJust() {
  fmt.Printf("Say : %v\n", canBeString.String());
 } else {
  fmt.Print("Nothing to say !\n");
 }
}

func sayMaybeNothing (canBeString maybe.AString) {
 fmt.Printf("Say : %v\n", canBeString.OrDefault("nothing"));
}

func main() {
 aString := maybe.String("hello");
 say(aString);
 sayMaybeNothing(aString);
 noString := maybe.NoString;
 say(noString);
 sayMaybeNothing(noString);
}
ppierre
+1  A: 

I thought some more about how I would implement this using a struct. Here's what I came up with:

type MyString struct {
    val string;
}

func f(s MyString) {
    if s == nil {
        s = MyString{"some default"};
    }
    //do something with s.val
}

Then you can call f like this:

f(nil);
f(MyString{"not a default"});
Bill Ayakatubby
A: 

Loose the Java-think and just pass f(""). Then test using len():

func f(str string) { if len(str) > 0 { ... } else { ... } }

Either the string is empty and has semantic meaning of you nil case, or else has some string data to process. Can't see the problem with that.

RogerV
The problem is that you may have null strings as ordinary parameters, not meaning "the default". What you suggest is "in-band signaling" (like using 0 or -1 for an integer) and is widely seen as a bad idea because you may need the "special" value for an ordinary meaning.
bortzmeyer