# 11 接口(Interface)

接口就是定义了一组方法的类型。

接口是对行为的抽象。

例如，标准库中定义了`io.Reader`接口：

```go
type Reader interface {
    Read(d []byte) (int, error)
}
```

绝大多数操作二进制数据流的函数(比如JSON解码器)都是把`io.Reader`作为数据来源。这样，我们就可以为物理文件、内存中的字节、网络连接等实现`Reader`接口，使`json.Decode`可以处理这些数据。

下面展示了如何定义和实现一个简单接口：

```go
package main

import (
	"fmt"
	"strconv"
)

// Stringer就是一个接口,它里面只包含了1个函数
type Stringer interface {
	String() string
}

// User结构体是准备用来实现Stringer接口的
type User struct {
	Name string
}

func (u *User) String() string {
	return u.Name
}

// 任何类型都可以实现某个接口。 
// 这里我们创建一个int类型的别名,然后用它实现Stringer接口

type MyInt int

func (mi MyInt) String() string {
	return strconv.Itoa(int(mi))
}

// printTypeAndString 函数接收一个接口。
// 's' 可以是任何实现了Stringer接口的类型的值。
func printTypeAndString(s Stringer) {
	fmt.Printf("%T: %s\n", s, s)
}

func main() {
	u := &User{Name: "John"}
	printTypeAndString(u)

	n := MyInt(5)
	printTypeAndString(n)
}
```

上述代码的输出： :point\_right: [点击此处](https://play.golang.org/p/ba83kFxk4Yg) :point\_left: 亲自尝试执行代码。

```go
*main.User: John
main.MyInt: 5
```

跟其他大多数语言都不同，Go的接口是被隐式实现的。

我们不需要显式地声明`struct User`要实现`Stringer`接口。

接口只可以包含方法，不可以包含数据。如果您想既复用方法又复用数据，请使用[结构体嵌入](/essential-go/10-structs/composition-and-embedding.md)。

您只能在定义类型的包里面为该类型定义方法。我们刚才先定义了`MyInt`类型然后才为它定义方法，是因为不允许直接为内置类型定义方法。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://denglj.gitbook.io/essential-go/11-interfaces.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
