最近在学习单链表的时候,在创建完Node节点之后,链表的表示是新建一个struct,如下
```
type List1 struct {
Head *Node
}
```
这样做完全没问题。可是我看的是<<数据结构与算法分析C语言>>版本的,就想着用类似C的typedef来实现下单链表,所以就有了以下代码
```声明一个新类型list2
type list2 *Node
```
这样的类型声明看着完全没问题.继续写,来一个判断单链表是否是空表的方法,很容易写出一下代码。
```
func (l list2) isEmpty() bool {
return l.Next == nil
}
```
但是编译器在这里却报了个错误.
> [go] invalid receiver type list2(list2 is a pointer type)
直译出来就是:因为list2是指针类型,所以这是个无效的方法接受者
在stackoverflow找到这一段解释
> The receiver type must be of the form T or *T where T is a type name. The type denoted by T is called the receiver base type; it must not be a pointer or interface type and it must be declared in the same package as the method.
**大致意思就是在Go中,方法的接受者可以是T或者*T类型的,这里T不能是指针类型或接口类型.**
既然这种类型声明出来的新类型不符合条件,那么我们可以用一下方法写
```
type list2 Node
func (l *list2) isEmpty() bool {
return l.Next == nil
}
```
**这样写虽然可以让代码运行,但是却不符合链表的定义,在<<数据结构与算法分析C语言>>中,C的typedef出来的类型其实是指针类型的,这里只是代码运行无误,却不合乎定义,而且,为了预防调用这使用强制类型转化带来的错误,要慎用这种类型声明**
既然类型申明用不了,那来试试类型命名
> 类型别名和原类型完全一样,只不过是另一种叫法而已
有兴趣的可以看下这篇文章 https://talks.golang.org/2016/refactor.article
> 文章主要讲的是:在大规模的重构项目代码的时候,尤其是将一个类型从一个包移动到另一个包中的时候,有些代码使用新包中的类型,有些代码使用旧包中的类型;类型别名会十分方便、有效
```
type list2 = *Node
func (l list2) isEmpty() bool {
return l.Next == nil
}
```
代码上来看无任何问题,并且链表list也是*Node类型的。可以实现链表的功能。
再来看下go内置的双链表的实现,源码在"container/list"下
```
type Element struct {
next, prev *Element
list *List
Value interface{}
}
type List struct {
root Element
len int
}
```
可以看到go官方的链表也是新建一个新类型出来,并非使用类型命名或者类型定义,而且链表中还自带len字段,在查找链表长度时很方便,不用去遍历来实现链表的长度。
#### 来模仿官方源码来写一个单链表
* **1.无头节点**
```
type list struct {
len int
root *Node
}
```
* **2.有头节点**
带有头节点的单链表也可以有两种写法
* 第一种就是把链表的长度当作链表的字段来存放
```
type list struct {
len int
root *Node
}
```
* 第二种就是链表的长度存放在头节点的数据域中,如数据源是int,int8...等类型的时候
```
type list3 struct {
head *Node
}
```
这里head不能为nil,并且head.Data 存放链表长度,head.Next存放第一个有效的节点
[博客地址](https://github.com/zgjff/Blog/issues/2)