golang 有哪些数据类型

interface 是一种数据类型吗,答案是:是。

golang 语言有四种数据类型,分别是

  • 基本类型(basic)
    • 数字
    • 字符串
    • 布尔型
  • 聚合类型(aggregate)
    • 数组
    • struct
  • 复合类型(reference)
    • 指针
    • slice
    • map
    • 函数
    • channel
  • 接口类型(interface)

什么是方法

方法是定义在一个数据类型上面的函数,可以类比为 “面向对象中,类中的方法”。

方法和这个数据类型需要处于同一个包里,所以对于内置类型,如 int,需要从他定义一个数据类型,

type CountNum int

然后再在这个新的数据类型上定义方法

func (c CountNum) Print {
    fmt.Printf("CountNum is %d", i)
}

最常用的就是在 struct 上定义方法

type Person struct {
	Name string
	Age int
}

func (p Person) Get {
  return fmt.Sprintf("Person name: %6s, age: %4d", p.Name, p.Age)
}

使用方法修改所定义的数据类型的数据

func (p Person) Set(name string) {
	p.Name = name
}

如果直接这么写,是有问题的。

因为在 golang 中是参数是值传递,所以在上面这个方法里,收到了类型为Person的一个值的拷贝p,然后对p做了修改,是无法传递出去的。

所以需要改为传递指针变量:

func (p *Person) Set(name string) {
	p.Name = name
}

这样就可以通过指针修改原来的数据。

事实上,指针仍然是值传递,但是,哈哈,拷贝的指针指向的地方是不变的,是依然可以修改的。

怎么定义一个 interface

划重点:接口的定义是方法的声明的集合,接口的实现是方法的实现的集合

所以我刚刚先说了方法。

和方法不一样的是,接口并不是定义在具体的类型上面的(方法是这样的)。

同一个接口可以在不同数据类型上实现,取决于你想要怎么搞了。

这里我先定义一个接口:

type GetSet interface {
    Get() string
    Set(string)
}

这个接口声明了两个方法:Get() string,Set(string),这两个方法合起来(interface{ })就构成了一个接口,这个接口的名字叫做GetSet

怎么实现一个 interface

说明

golang 这门语言的接口与其他语言的不同之处在于,golang 的接口是隐式实现的。

这是什么意思呢?

意思就是你不需要显式的这么做:

class SomeClass implements SomeInterface {

}

那怎么做

刚刚说了:「接口的实现是方法的实现的集合」,方法是定义在数据类型上面的,所以先给出一个数据类型:

type Person struct {
	Name string
	Age  int
}

然后对这个数据类型实现接口定义里面所有声明的方法,也就是:Get() string,Set(string)

func (p *Person) Get() string {
	return fmt.Sprintf("Person name: %6s, age: %4d", p.Name, p.Age)
}

func (p *Person) Set(name string) {
	p.Name = name
}

断言是否实现了接口

ok,到这里为止,我定义了一个接口GetSet,然后用Person实现了这个接口,一切都很美好,问题是,我真的实现了这个接口了吗?

有一个简单的方法去判断:

var _ GetSet = new(Person) // var _ GetSet = Person{}

这是一个断言:Person的一个值实现了接口GetSet,如果Person没有实现了接口GetSet,编译的时候就会报错。

实际上,我们不需要创建一个变量(new(Person)),因为Person是任意值都实现了这个接口,所以nil也实现了,所以可以用类型转化做断言,代码如下:

var _ GetSet = (*Person)(nil)

空 interface 是什么

什么是空接口:

interface{}

上面说过,接口是声明的方法的集合,空接口没有声明方法,所以任何类型都实现了空接口。

所以一个函数可以使用interface{}接受任意类型的值作为参数,也可以使用interface{}将任意类型的值作为返回值。