有志者,事竟成!如果你在学习Golang,那么本文《空接口是绕过类型系统的一种方法吗?》,就很适合你!文章讲解的知识点主要包括,若是你对本文感兴趣,或者是想搞懂其中某个知识点,就请你继续往下看吧~
问题内容我正在学习 go(来自 python),强制类型系统实际上很有帮助。我对 interface{}
的理解非常有限,因此我得到了以下代码,我在其中从 api 检索 json 数据并返回已解析的版本。结果可以是一个对象或对象列表。
func getJsonFromApi(endpoint string) (reply interface{}, err error) {
res, err := http.Get("http://127.0.0.42/api/" + endpoint)
if err != nil {
return nil, err
}
body, err := ioutil.ReadAll(res.Body)
err = res.Body.Close()
if err != nil {
return nil, err
}
err = json.Unmarshal(body, &reply)
return reply, nil
}
它有效,但我对破坏类型系统感到不舒服。这是 interface{}
的预期用途吗?
我最终将更改代码以始终返回对象数组(并在第一个用例中获取第一个对象),但我对一般问题感到好奇。
正确答案
空接口 interface{}
是一个指定零方法的接口。它可以保存任何类型的值 (https://tour.golang.org/methods/14),因此您可以在不知道实际类型的情况下使用它来保存某些内容。
有时在像您这样的示例中这是必要的,但代价是强类型。我认为在您的示例中使用它不应该感到不舒服,但是如果它最终到处都是,您应该开始感到不舒服。
如果您使用此签名,则可以允许方法的调用者传入实际类型:
func getjsonfromapi(endpoint string, reply interface{}) (err error) {
我想说它是类型系统的一部分,而不是绕过它的方法。
如果可能,最好使用 struct
。您可以使用 map
:
package main
import (
"encoding/json"
"net/http"
)
func main() {
r, e := http.get("https://github.com/manifest.json")
if e != nil {
panic(e)
}
defer r.body.close()
m := make(map[string]interface{})
json.newdecoder(r.body).decode(&m)
s := m["icons"].([]interface{})[0].(map[string]interface{})["sizes"].(string)
println(s == "114x114")
}
但正如您所看到的,当您需要打开包装以获得实际值时,它会变得非常痛苦。 struct
好多了:
package main
import (
"encoding/json"
"net/http"
)
func main() {
r, e := http.Get("https://github.com/manifest.json")
if e != nil {
panic(e)
}
defer r.Body.Close()
var m struct {
Icons []struct { Sizes string }
}
json.NewDecoder(r.Body).Decode(&m)
s := m.Icons[0].Sizes
println(s == "114x114")
}
到这里,我们也就讲完了《空接口是绕过类型系统的一种方法吗?》的内容了。个人认为,基础知识的学习和巩固,是为了更好的将其运用到项目中,欢迎关注编程网公众号,带你了解更多关于的知识点!