20210103结合net http.HandlerFunc函数类型总结golang的类型匹配原则(那篇文章的思想是错的) - ziyouzy/2021blog GitHub Wiki

把最重要的事说在前边,这篇文章中所解释的强制的使用动机、理由是错误的:

https://blog.csdn.net/a_flying_bird/article/details/52536258

文章中的原话是:

习惯上,先定义自己的符合如下前面的函数:
func(ResponseWriter, *Request)
然后通过“类型转换”,将该函数转换成HandlerFunc类型,从而就变成了Handler对象。
handler := http.HandlerFunc(msgHandler)

我们先来明确golang的一个语言特性,那就是golang的类型转换没有隐式类型转换,只有强制类型转换和类型断言

具体请看如下文章的解释

https://studygolang.com/articles/21591?fr=sidebar

因此源代码的这句 handler := http.HandlerFunc(msgHandler)虽然说他确实做了“类型转换”但是其实并不严谨,应该说他做的是“强制类型转换”

但是经过实现,也已经证明如下写法也是可行的:

func msgHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprint(w, "Hello, HandlerFunc!")
}

func main() {
var handler http.HandlerFunc = msgHandler
}

因此可以理解成,这里存在两种效果相同,但是原理不同,且同时可行的两个操作:

一个是强制类型转换

另一个是类似把一个结构体赋值给接口的操作,或者也是之前所实验过的:
某个map与他的别名之间的相互赋值、某个切片/数组与他的别名之间的相互赋值、某个函数与他的别名之间的相互符值

这里又找到了篇新文章,仿佛打开了新世界的大门

http://c.biancheng.net/view/25.html

这里给别名做了个明确的定义:

“类型别名规定:TypeAlias 只是 Type 的别名,本质上 TypeAlias 与 Type 是同一个类型,就像一个孩子小时候有小名、乳名,上学后用学名,英语老师又会给他起英文名,但这些名字都指的是他本人”

因此对于HandlerFunc这个例子来说也就不难理解为什么无论是强制转换还是直接赋值都是可以的

因此和我预想的一致,这里源代码中的强制转换操作其实是为了和":="语法糖搭配使用,从而大大减少代码书写量罢了

再次验证了一下,结构类确实不行:

type S struct{
a int
b int
}

type newS S

func main() {
s1 := newS(S{a:1,b:2}) 
fmt.Println(s1)

s2 :=S{a:2,b:3}
fmt.Println(s2)

s3 := newS{a:4,b:5}
fmt.Println(s3)

s2 =s3
}