英文:
How to have a function with a nullable string parameter in Go?
问题
我习惯于Java的String,我们可以传递null而不是""来表示特殊含义,比如使用默认值。
在Go中,string是一种原始类型,所以我不能将nil(null)传递给需要string类型参数的函数。
我可以使用指针类型来编写函数,像这样:
func f(s *string)
这样调用者可以这样调用该函数:
f(nil)
或者
// 不太优雅
temp := "hello";
f(&temp)
但是以下方式不被允许:
// 优雅但不被允许
f(&"hello");
有什么最好的方法可以接收string或者nil作为参数?
英文:
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?
答案1
得分: 5
警告:以下是Go1之前的代码。也就是说,它来自一个预发布版本,不是有效的Go代码。
我再考虑了一下如何使用struct
来实现这个。这是我想出来的:
type MyString struct {
val string;
}
func f(s MyString) {
if s == nil {
s = MyString{"一些默认值"};
}
//对s.val进行操作
}
然后你可以这样调用f
:
f(nil);
f(MyString{"不是默认值"});
英文:
Warning: the following is pre-Go1 code. That is, it's from a pre-release version and is not valid Go code.
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"});
答案2
得分: 3
如果您需要处理可能的空值(例如,因为您正在与可能提供它们的数据库交互),database/sql
包提供了诸如 sql.NullString
和 sql.NullInt64
等类型,它们允许您使用它们的 .Valid
字段测试是否提供了值。
英文:
If you need to handle a possibble null value (becasue you are talking to a database that may provide them for example) the database/sql
package has types such as sql.NullString
and sql.NullInt64
that allow you to test if you have been provided with a value or not using their .Valid
field.
答案3
得分: 1
不真正参与回答:但是在结构中包装值可以提供一些通用的实用方法。 (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("访问不存在的maybeString值");
}
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("说:%v\n", canBeString.String());
} else {
fmt.Print("没什么可说的!\n");
}
}
func sayMaybeNothing(canBeString maybe.AString) {
fmt.Printf("说:%v\n", canBeString.OrDefault("nothing"));
}
func main() {
aString := maybe.String("你好");
say(aString);
sayMaybeNothing(aString);
noString := maybe.NoString;
say(noString);
sayMaybeNothing(noString);
}
英文:
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);
}
答案4
得分: 1
你可以声明一个接口来限制类型为string
,并且由于接口也接受nil
,所以你可以覆盖两种情况。以下是实现的方式:
type (
// 一个接受字符串或nil值的接口。
//
// 你可以传递StrVal("text")或nil。
StrOrNil interface{ isStrOrNil() }
StrVal string // StrOrNil接口的字符串值。
)
func (StrVal) isStrOrNil() {} // 实现接口
以下是如何使用它:
func Foo(name StrOrNil) {
switch nameVal := name.(type) {
case StrVal:
fmt.Printf("字符串值!%s\n", string(nameVal))
default:
fmt.Println("空值!")
}
}
func main() {
Foo(StrVal("hello world"))
Foo(nil)
}
在playground中测试它。
英文:
You can declare an interface to restrict the type to string
, and since interfaces also accept nil
, you'd have both cases covered. This is how you can implement it:
type (
// An interface which accepts a string or a nil value.
//
// You can pass StrVal("text") or nil.
StrOrNil interface{ isStrOrNil() }
StrVal string // A string value for StrOrNil interface.
)
func (StrVal) isStrOrNil() {} // implement the interface
And this is how you use it:
func Foo(name StrOrNil) {
switch nameVal := name.(type) {
case StrVal:
fmt.Printf("String value! %s\n", string(nameVal))
default:
fmt.Println("Null value!")
}
}
func main() {
Foo(StrVal("hello world"))
Foo(nil)
}
Test it in the playground.
答案5
得分: -3
放弃Java思维,只需传递f("")。然后使用len()进行测试:
func f(str string) {
if len(str) > 0 {
...
} else {
...
}
}
字符串要么为空且具有nil情况的语义含义,要么具有一些字符串数据需要处理。看不出有什么问题。
英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论