如何检查嵌套指针中的值
How to check value in nested pointer
如何轻松检查嵌套指针?
type inner1 struct {
value string
}
type inner2 struct {
value *inner1
}
type outter struct {
value *inner2
}
我有这样的数据:
o := &outter{
value: &inner2{
value: &inner1{
value: "I need this data",
},
},
}
如果我想从中获取数据,我需要检查 nil 指针。
func printValue(o *outter) (string, bool) {
if o.value != nil {
v1 := o.value
if v1.value != nil {
v2 := v1.value
return v2.value, true
}
}
return "", false
}
是的,我可以做到。但在我的真实场景中,这个嵌套指针部分要长得多。我会更喜欢另一种方式。
我已经检查了这个答案,。但我需要替代方案。
我怎样才能做到这一点。有什么更有效和更好的选择吗?
我可以使用紧急恢复方法。这将解决我的问题。但这对我来说似乎很老套。
func printValue(o *outter) (string, bool) {
defer func() (string, bool) {
if r := recover(); r != nil {
return "", false
}
return "", false
}()
return o.value.value.value, true
}
Panic and recover 用于特殊情况。检查指针是否为 nil
通常不是,所以你应该远离它。使用 if
语句检查指针是否为 nil
比使用 recover()
引入延迟函数要简洁得多。特别是因为这个 recover()
将阻止所有其他类型的恐慌,即使是那些由其他原因而不是试图取消引用 nil
指针引起的恐慌。 (使用 defer
和 recover()
也比使用 if
的简单 nil
检查慢。)
如果数据总是需要非nil
值,你应该考虑不为它使用指针。如果数据总是需要非 nil
但由于某种原因你需要使用指针,那么如果任何指针仍然是 [=15,那么这可能是让你的代码恐慌的有效案例=].
如果可能是nil
,那你就要检查一下nil
的情况,妥善处理。你必须明确这一点,Go 不会帮你省略这个检查。
为了避免在每个地方都检查nil
,实用函数或方法是合理的。请注意,即使接收者是 nil
也可以调用方法,这在这种情况下可能很有用。
例如,您可以附加以下方法:
func (i *inner1) Get() (string, bool) {
if i == nil {
return "", false
}
return i.value, true
}
func (i *inner2) Get() (string, bool) {
if i == nil {
return "", false
}
return i.value.Get()
}
func (o *outter) Get() (string, bool) {
if o == nil {
return "", false
}
return o.value.Get()
}
请注意,每个 Get()
方法都需要检查单个指针,无论数据结构有多复杂。
正在测试:
o := &outter{
value: &inner2{
value: &inner1{
value: "I need this data",
},
},
}
fmt.Println(o.Get())
o.value.value = nil
fmt.Println(o.Get())
o.value = nil
fmt.Println(o.Get())
o = nil
fmt.Println(o.Get())
输出(在 Go Playground 上尝试):
I need this data true
false
false
false
上述解决方案隐藏了 outter
的内部结构,这对那些使用outter
的人很有用(如果 outter
的内部结构不需要更新客户端=33=]改变,只是outter.Get()
方法)。
类似的方法是添加仅 return 接收者结构字段的方法:
func (i *inner1) Value() (string, bool) {
if i == nil {
return "", false
}
return i.value, true
}
func (i *inner2) Inner1() *inner1 {
if i == nil {
return nil
}
return i.value
}
func (o *outter) Inner2() *inner2 {
if o == nil {
return nil
}
return o.value
}
此方法要求客户了解 outter
的内部结构,但同样在使用时不需要任何 nil
检查:
o := &outter{
value: &inner2{
value: &inner1{
value: "I need this data",
},
},
}
fmt.Println(o.Inner2().Inner1().Value())
o.value.value = nil
fmt.Println(o.Inner2().Inner1().Value())
o.value = nil
fmt.Println(o.Inner2().Inner1().Value())
o = nil
fmt.Println(o.Inner2().Inner1().Value())
输出相同。在 Go Playground.
上试试这个
没有简单的方法。您可以恢复方式,但这不是惯用的 IMO,您应该检查您是否没有发现其他不相关的错误。
我更喜欢一个 if
而不是多个。我不认为下面的代码丑陋或冗长。
func printValue(o *outter) (string, bool) {
if o.value != nil and o.value.value != nil and o.value.value.value != nil {
return *o.value.value.value, true
}
return "", false
}
使用反射
func getFieldByName(v interface{}, fields string, sep string) interface{} {
r := reflect.ValueOf(v)
s := strings.Split(fields, sep)
for _, field := range s {
r = reflect.Indirect(r)
if r.IsValid() {
r = reflect.Indirect(r).FieldByName(field)
} else {
return nil
}
}
if r.IsValid() {
return r.Interface()
}
return nil
}
使用紧急恢复
type safeGetFn func() interface{}
func safeGet(f safeGetFn, d interface{}) (ret interface{}) {
defer func() interface{} {
if r := recover(); r != nil {
ret = d
}
return ret
}()
return f()
}
如何轻松检查嵌套指针?
type inner1 struct {
value string
}
type inner2 struct {
value *inner1
}
type outter struct {
value *inner2
}
我有这样的数据:
o := &outter{
value: &inner2{
value: &inner1{
value: "I need this data",
},
},
}
如果我想从中获取数据,我需要检查 nil 指针。
func printValue(o *outter) (string, bool) {
if o.value != nil {
v1 := o.value
if v1.value != nil {
v2 := v1.value
return v2.value, true
}
}
return "", false
}
是的,我可以做到。但在我的真实场景中,这个嵌套指针部分要长得多。我会更喜欢另一种方式。
我已经检查了这个答案,
我怎样才能做到这一点。有什么更有效和更好的选择吗?
我可以使用紧急恢复方法。这将解决我的问题。但这对我来说似乎很老套。
func printValue(o *outter) (string, bool) {
defer func() (string, bool) {
if r := recover(); r != nil {
return "", false
}
return "", false
}()
return o.value.value.value, true
}
Panic and recover 用于特殊情况。检查指针是否为 nil
通常不是,所以你应该远离它。使用 if
语句检查指针是否为 nil
比使用 recover()
引入延迟函数要简洁得多。特别是因为这个 recover()
将阻止所有其他类型的恐慌,即使是那些由其他原因而不是试图取消引用 nil
指针引起的恐慌。 (使用 defer
和 recover()
也比使用 if
的简单 nil
检查慢。)
如果数据总是需要非nil
值,你应该考虑不为它使用指针。如果数据总是需要非 nil
但由于某种原因你需要使用指针,那么如果任何指针仍然是 [=15,那么这可能是让你的代码恐慌的有效案例=].
如果可能是nil
,那你就要检查一下nil
的情况,妥善处理。你必须明确这一点,Go 不会帮你省略这个检查。
为了避免在每个地方都检查nil
,实用函数或方法是合理的。请注意,即使接收者是 nil
也可以调用方法,这在这种情况下可能很有用。
例如,您可以附加以下方法:
func (i *inner1) Get() (string, bool) {
if i == nil {
return "", false
}
return i.value, true
}
func (i *inner2) Get() (string, bool) {
if i == nil {
return "", false
}
return i.value.Get()
}
func (o *outter) Get() (string, bool) {
if o == nil {
return "", false
}
return o.value.Get()
}
请注意,每个 Get()
方法都需要检查单个指针,无论数据结构有多复杂。
正在测试:
o := &outter{
value: &inner2{
value: &inner1{
value: "I need this data",
},
},
}
fmt.Println(o.Get())
o.value.value = nil
fmt.Println(o.Get())
o.value = nil
fmt.Println(o.Get())
o = nil
fmt.Println(o.Get())
输出(在 Go Playground 上尝试):
I need this data true
false
false
false
上述解决方案隐藏了 outter
的内部结构,这对那些使用outter
的人很有用(如果 outter
的内部结构不需要更新客户端=33=]改变,只是outter.Get()
方法)。
类似的方法是添加仅 return 接收者结构字段的方法:
func (i *inner1) Value() (string, bool) {
if i == nil {
return "", false
}
return i.value, true
}
func (i *inner2) Inner1() *inner1 {
if i == nil {
return nil
}
return i.value
}
func (o *outter) Inner2() *inner2 {
if o == nil {
return nil
}
return o.value
}
此方法要求客户了解 outter
的内部结构,但同样在使用时不需要任何 nil
检查:
o := &outter{
value: &inner2{
value: &inner1{
value: "I need this data",
},
},
}
fmt.Println(o.Inner2().Inner1().Value())
o.value.value = nil
fmt.Println(o.Inner2().Inner1().Value())
o.value = nil
fmt.Println(o.Inner2().Inner1().Value())
o = nil
fmt.Println(o.Inner2().Inner1().Value())
输出相同。在 Go Playground.
上试试这个没有简单的方法。您可以恢复方式,但这不是惯用的 IMO,您应该检查您是否没有发现其他不相关的错误。
我更喜欢一个 if
而不是多个。我不认为下面的代码丑陋或冗长。
func printValue(o *outter) (string, bool) {
if o.value != nil and o.value.value != nil and o.value.value.value != nil {
return *o.value.value.value, true
}
return "", false
}
使用反射
func getFieldByName(v interface{}, fields string, sep string) interface{} {
r := reflect.ValueOf(v)
s := strings.Split(fields, sep)
for _, field := range s {
r = reflect.Indirect(r)
if r.IsValid() {
r = reflect.Indirect(r).FieldByName(field)
} else {
return nil
}
}
if r.IsValid() {
return r.Interface()
}
return nil
}
使用紧急恢复
type safeGetFn func() interface{}
func safeGet(f safeGetFn, d interface{}) (ret interface{}) {
defer func() interface{} {
if r := recover(); r != nil {
ret = d
}
return ret
}()
return f()
}