如何将 nil 接口转换为 nil 其他接口

Posted

技术标签:

【中文标题】如何将 nil 接口转换为 nil 其他接口【英文标题】:How to cast nil interface to nil other interface 【发布时间】:2020-01-06 21:56:44 【问题描述】:

我有一个经典的 Go nil 界面问题。

我正在尝试将我从nil error 分配的interface 断言回error 接口。这句话令人困惑,所以我有一个方便的例子:https://play.golang.com/p/Qhv7197oIE_z

package main

import (
    "fmt"
)

func preferredWay(i interface) error 
    return i.(error)


func workAround(i interface) error 
    if i == nil 
        return nil
    
    return i.(error)


func main() 
    var nilErr error
    fmt.Println(workAround(nilErr))    // Prints "<nil>" as expected.
    fmt.Println(preferredWay(nilErr))  // Panics.

输出:

<nil>
panic: interface conversion: interface is nil, not error

goroutine 1 [running]:
main.preferredWay(...)
    /tmp/sandbox415300914/prog.go:8
main.main()
    /tmp/sandbox415300914/prog.go:21 +0xa0

换句话说,我试图从nil interface 向下转换为nil error 接口。如果我知道 interface 被分配为 nil error 开始,是否有一种优雅的方法可以做到这一点?

仅供参考,如果这看起来不寻常,那是因为我正在实施一些模拟测试。

【问题讨论】:

无论值是否为nil,在执行type assertion 时,请使用逗号-ok 习惯用法以避免出现恐慌。 (参见文档链接部分的最后一段) 考虑到我的用例,我不介意恐慌。我将它用于模拟客户端,因此在实施测试时,我可以为模拟客户端方法设置返回值。在这种情况下,恐慌实际上是有帮助的,因为恐慌很快就会失败,这意味着我的测试实施不正确。 【参考方案1】:

这行得通吗?

func preferredWay(i interface) error 
    k, _ := i.(error)
    return k

【讨论】:

在这种情况下似乎是一个好方法。不过,我很好奇 nil 接口上类型断言的语义。甚至var i interface; i.(interface) 都惊慌失措。 在这种情况下,i 是 nil,所以类型断言恐慌,因为它查看接口的值,但值是 nil。 v,_:=i.(interface) 不会恐慌,因为 if 首先检查 i 是否可以转换为接口。如果 i 是具有 nil 值的非 nil 接口,则类型断言不会失败。 @ScottCrunkleton 这和nil这个值关系不大,问题是niluntyped的,即"的类型存储在i 中的非值”不是interface,不是任何东西,所以i.(interface) 失败,没有, ok 它会恐慌。尝试给i 一个typed nil,然后断言i 给那个类型,它仍然恐慌吗?不,它没有。 play.golang.com/p/_xFk0jX5YIW 一个接口有一对引用,一个类型的引用和一个值的引用。如果接口本身是 nil,那么这些都是 nil。如果接口指向一个 nil 值,那么类型是非 nil(它指向 nil 值的类型),但值是 nil。如果接口是第一类,类型断言失败,因为类型为 nil。如果接口是第二种类型,则类型断言有效,因为存在非 nil 类型。 @bserdar +1 你的解释比我的尝试更准确、更清晰。

以上是关于如何将 nil 接口转换为 nil 其他接口的主要内容,如果未能解决你的问题,请参考以下文章

无法将 nil 转换为确切的数字

golang 将接口值与#golang中的nil进行比较

Go“一个包含nil指针的接口不是nil接口”踩坑

如何将 DateTime 的 SQL Server XML 类型值 (xsi:nil) 转换为 null

将 NSManagedObject 转换为子类返回 nil

将 NSData 转换为 NSString 返回 nil