英文:
How to check for an empty struct?
问题
我定义了一个结构体...
type Session struct {
playerId string
beehive string
timestamp time.Time
}
有时我会给它赋一个空的session(因为不能使用nil)
session = Session{};
然后我想检查它是否为空:
if session == Session{} {
// 做一些操作...
}
显然这样是行不通的。我该如何编写它?
英文:
I define a struct ...
type Session struct {
playerId string
beehive string
timestamp time.Time
}
Sometimes I assign an empty session to it (because nil is not possible)
session = Session{};
Then I want to check, if it is empty:
if session == Session{} {
// do stuff...
}
Obviously this is not working. How do I write it?
答案1
得分: 314
你可以使用==
运算符将Session
与零值组合字面量进行比较,因为Session
中的所有字段都是可比较的:
if (Session{}) == session {
fmt.Println("是零值")
}
由于解析歧义,在if条件中需要使用括号将组合字面量括起来。
上述使用==
的方法适用于所有字段都是可比较的的结构体。如果结构体包含一个非可比较的字段(切片、映射或函数),那么必须逐个比较字段与它们的零值。
与比较整个值相比,另一种方法是比较必须在有效会话中设置为非零值的字段。例如,如果在有效会话中玩家ID必须为""
之外的值,可以使用以下代码:
if session.playerId == "" {
fmt.Println("是零值")
}
英文:
You can use == to compare with a zero value composite literal because all fields in Session
are comparable:
if (Session{}) == session {
fmt.Println("is zero value")
}
Because of a parsing ambiguity, parentheses are required around the composite literal in the if condition.
The use of ==
above applies to structs where all fields are comparable. If the struct contains a non-comparable field (slice, map or function), then the fields must be compared one by one to their zero values.
An alternative to comparing the entire value is to compare a field that must be set to a non-zero value in a valid session. For example, if the player id must be != "" in a valid session, use
if session.playerId == "" {
fmt.Println("is zero value")
}
答案2
得分: 64
以下是3个更多的建议或技巧:
使用额外的字段
您可以添加一个额外的字段来判断结构体是否已经填充或为空。我故意将其命名为ready
而不是empty
,因为bool
类型的零值是false
,所以如果您创建一个新的结构体Session{}
,它的ready
字段将自动为false
,并且它会告诉您真相:该结构体尚未准备好(为空)。
type Session struct {
ready bool
playerId string
beehive string
timestamp time.Time
}
当您初始化结构体时,必须将ready
设置为true
。您不再需要isEmpty()
方法(尽管如果您愿意,仍然可以创建一个),因为您可以直接测试ready
字段本身。
var s Session
if !s.ready {
// do stuff (populate s)
}
当结构体变得更大或包含不可比较的字段(例如切片、map
和函数值)时,这个额外的bool
字段的重要性会增加。
使用现有字段的零值
这与前面的建议类似,但它使用现有字段的零值,在结构体为空时被视为“无效”。这个方法的可用性取决于具体实现。
例如,如果在您的示例中,playerId
不能是空字符串""
,您可以使用它来测试结构体是否为空:
var s Session
if s.playerId == "" {
// do stuff (populate s, give proper value to playerId)
}
在这种情况下,值得将此检查合并到一个isEmpty()
方法中,因为这个检查是依赖于具体实现的:
func (s Session) isEmpty() bool {
return s.playerId == ""
}
并使用它:
if s.isEmpty() {
// do stuff (populate s, give proper value to playerId)
}
使用指向结构体的指针
第二个建议是使用指向结构体的指针:*Session
。指针可以具有nil
值,因此您可以测试它:
var s *Session
if s == nil {
s = new(Session)
// do stuff (populate s)
}
英文:
Here are 3 more suggestions or techniques:
With an Additional Field
You can add an additional field to tell if the struct has been populated or it is empty. I intentionally named it ready
and not empty
because the zero value of a bool
is false
, so if you create a new struct like Session{}
its ready
field will be automatically false
and it will tell you the truth: that the struct is not-yet ready (it's empty).
type Session struct {
ready bool
playerId string
beehive string
timestamp time.Time
}
When you initialize the struct, you have to set ready
to true
. Your isEmpty()
method isn't needed anymore (although you can create one if you want to) because you can just test the ready
field itself.
var s Session
if !s.ready {
// do stuff (populate s)
}
Significance of this one additional bool
field increases as the struct grows bigger or if it contains fields which are not comparable (e.g. slice, map
and function values).
Using the Zero Value of an Existing Field
This is similar to the previous suggestion, but it uses the zero value of an existing field which is considered invalid when the struct is not empty. Usability of this is implementation dependant.
For example if in your example your playerId
cannot be the empty string
""
, you can use it to test if your struct is empty like this:
var s Session
if s.playerId == "" {
// do stuff (populate s, give proper value to playerId)
}
In this case it's worth incorporating this check into an isEmpty()
method because this check is implementation dependant:
func (s Session) isEmpty() bool {
return s.playerId == ""
}
And using it:
if s.isEmpty() {
// do stuff (populate s, give proper value to playerId)
}
Use Pointer to your struct
The second suggestion is to use a Pointer to your struct: *Session
. Pointers can have nil
values, so you can test for it:
var s *Session
if s == nil {
s = new(Session)
// do stuff (populate s)
}
答案3
得分: 33
只是一个快速的补充,因为我今天遇到了同样的问题:
在 Go 1.13 中,可以使用新的 isZero()
方法:
if reflect.ValueOf(session).IsZero() {
// 做一些操作...
}
我没有测试过这个方法的性能,但我猜想这应该比使用 reflect.DeepEqual()
进行比较更快。
英文:
Just a quick addition, because I tackled the same issue today:
With Go 1.13 it is possible to use the new isZero()
method:
if reflect.ValueOf(session).IsZero() {
// do stuff...
}
I didn't test this regarding performance, but I guess that this should be faster, than comparing via reflect.DeepEqual()
.
答案4
得分: 30
使用reflect.DeepEqual也可以工作,特别是当结构体内部有映射时。
package main
import "fmt"
import "time"
import "reflect"
type Session struct {
playerId string
beehive string
timestamp time.Time
}
func (s Session) IsEmpty() bool {
return reflect.DeepEqual(s, Session{})
}
func main() {
x := Session{}
if x.IsEmpty() {
fmt.Print("is empty")
}
}
英文:
Using reflect.deepEqual also works, especially when you have map inside the struct
package main
import "fmt"
import "time"
import "reflect"
type Session struct {
playerId string
beehive string
timestamp time.Time
}
func (s Session) IsEmpty() bool {
return reflect.DeepEqual(s,Session{})
}
func main() {
x := Session{}
if x.IsEmpty() {
fmt.Print("is empty")
}
}
答案5
得分: 8
请注意,使用指向结构体的指针时,您需要对变量进行解引用,而不是将其与指向空结构体的指针进行比较:
session := &Session{}
if (Session{}) == *session {
fmt.Println("session is empty")
}
请查看此playground。
此外,您还可以看到,包含指针切片属性的结构体不能以相同的方式进行比较...
英文:
Keep in mind that with pointers to struct you'd have to dereference the variable and not compare it with a pointer to empty struct:
session := &Session{}
if (Session{}) == *session {
fmt.Println("session is empty")
}
Check this playground.
Also here you can see that a struct holding a property which is a slice of pointers cannot be compared the same way...
答案6
得分: 2
作为对其他答案的替代方案,可以使用与您最初打算的方式类似的语法,通过case
语句而不是if
语句来实现:
session := Session{}
switch {
case Session{} == session:
fmt.Println("zero")
default:
fmt.Println("not zero")
}
英文:
As an alternative to the other answers, it's possible to do this with a syntax similar to the way you originally intended if you do it via a case
statement rather than an if
:
session := Session{}
switch {
case Session{} == session:
fmt.Println("zero")
default:
fmt.Println("not zero")
}
1: https://play.golang.org/p/kgIqmRnA2M "playground example"
答案7
得分: 0
@cerise-limón的答案是最好的。不过,如果你遇到像下面这样的struct containing ... cannot be compared
错误。
type Friends struct {
nice []string
mute []string
}
type Session struct {
playerId string
beehive string
timestamp time.Time
friends Friends
}
func main() {
session := Session{}
if (Session{}) == session {
fmt.Println("zero")
}
}
// 输出: ./prog.go:23:17: invalid operation: Session{} == session (struct containing Friends cannot be compared)
上述代码中,Friends
对象导致了错误。
简单的解决方法是在字段中将其定义为指针。
type Friends struct {
nice []string
mute []string
}
type Session struct {
playerId string
beehive string
timestamp time.Time
friends *Friends // <--- 在这里
}
func main() {
session := Session{}
if (Session{}) == session {
fmt.Println("zero")
}
}
// 输出: zero
英文:
@cerise-limón's answer was the best. Though, if you get struct containing ... cannot be compared
error like below.
type Friends struct {
nice []string
mute []string
}
type Session struct {
playerId string
beehive string
timestamp time.Time
friends Friends
}
func main() {
session := Session{}
if (Session{}) == session {
fmt.Println("zero")
}
}
// Output: ./prog.go:23:17: invalid operation: Session{} == session (struct containing Friends cannot be compared)
The above, Friends
' object is causing an error.
The easy way to fix it is to define as a pointer in the field.
type Friends struct {
nice []string
mute []string
}
type Session struct {
playerId string
beehive string
timestamp time.Time
friends *Friends // <--- here
}
func main() {
session := Session{}
if (Session{}) == session {
fmt.Println("zero")
}
}
// Output: zero
答案8
得分: 0
使用fmt.Sprintf
可以帮助检测一个struct
是否为空。当它为空时,输出结果为{ }
。
这个建议对于处理JSON和struct
没有特定名称的情况非常有用。
if fmt.Sprintf("%v", session) == "{ }" {
// session为空
}
英文:
Using fmt.Sprintf
can help to detect is a struct
empty or not. When it is empty the output is { }
.
This suggestion is useful for working with JSONs and where the struct
doesn't have a specific name.
if fmt.Sprintf("%v", session) == "{ }" {
// session is empty
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论