老师你好,视频中有这么一段代码:
type treeNode struct {
value int
}
func (node *treeNode) setValue(value int) {
if node == nil {
fmt.Println("setting value to nil node,ignored")
// 很神奇的是 假如我们没写下面的return语句
// 在go run 的时候会报错
// 但是 go build 不会报错 而是在执行生成的exe文件的时候会报错
return
}
node.value = value
}
func main() {
var pRoot *treeNode
pRoot.setValue(200)
}
作为一个C语言学的不好,只接触过JS/TS的人,我对这段代码有3点疑惑
1> nil是空指针的意思嘛?我搜索了一下,好像是指 指针变量还没确定到底指向谁的时候,这样的指针变量为空指针,C语言中常见于int *p = NULL
,其值为00000000 ?
2> 老师在视频里面说,当使用指针作为接收者的时候,并不是每次都要判断是否都要为nil的,可是实际上,在本节的代码中,traverse函数以及在下一节的视频(扩展已有结构)中,也是判断了指针接受者是否为nil的,我现在看到指针类型变量就心头一紧,我怎么感觉好像都需要判断是否为nil的情况呢?
3> 第三个问题最疑惑,如上的注释的部分所示,老师最开始在视频中忘记写了return, 但是,编辑器并没有提示错误,而是在运行的go run xxx.go 的时候才报错了,假如我们在TS中写null.setValue()
或者
type Foo = Bar | Null
const someFn = (param:Foo) => {
// 编辑器马上就可以提示你param可能为Null
param.someMethod()
}
这样一对比,明显是TS这种在你写代码的时候就提示风险的方式更好啊,为什么Go语言没有报错呢?
在traverse函数中
func (node *TreeNode) Traverse() {
if node == nil {
return
}
// 老师说,假如是在java或者c++中,需要写成
if(node.Left != nil){
node.Left.Traverse()
}
node.Print()
node.Right.Traverse()
}
对于上面的写法,老师的原话是: “nil也可以啊,它只是一个普通的函数啊,你只要判断了就行”,老师的意思是说,在这个函数开头我们就判断了node == nil的情况,所以下面直接写node.Left.Traverse(),此时node.Left就不可能为nil了,所以我们不需要这个If判断了,而C++/Java可能更严谨?所以需要我们再使用if语句来确保node.Left不为nil? 是这个意思吗 ? 相对来说我怎么感觉加个判断更好呢?或者说在TS里面:
type TreeNode = {
value: number
left: TreeNode | null
right: TreeNode | null
}
使用!或者?操作符
node.left!.Traverse()
// or
node.left?.Traverse()
这样也行啊,总的来说,我还是比较喜欢TS这种在你写代码的时候就可以提示你可能为null的写法,我暂时还感受不到为什么Go语言要弄成这种 写起来好像更简洁 但是实际上你在写的时候就要提醒自己考虑是否为nil的样子,多写了一点这个变量类型可能为null这一点点代码,你写的时候编辑器提醒你可能为null,这样不是更好吗?