Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

接口 #45

Open
kevinyan815 opened this issue Jan 12, 2021 · 0 comments
Open

接口 #45

kevinyan815 opened this issue Jan 12, 2021 · 0 comments

Comments

@kevinyan815
Copy link
Owner

kevinyan815 commented Jan 12, 2021

注:所有内容摘录自 Go 语言接口的实现原理,为该文章的读书笔记。

什么是接口

在计算机科学中,接口是系统中组件之间的边界或者叫接缝,不同的组件能够在边界上交换信息。接口的本质是引入一个新的中间层,调用方可以通过接口与具体实现分离,解除上下游的耦合,上层的模块不再需要依赖下层的具体模块,只需要依赖一个约定好的接口。

Java语言中的接口

很多面向对象语言都有接口这一概念,例如 Java 和 C#。Java 的接口不仅可以定义方法签名,还可以定义变量,这些定义的变量可以直接在实现接口的类中使用。

public interface MyInterface {
    public String hello = "Hello";
    public void sayHello();
}

上述代码定义了一个必须实现的方法 sayHello 和一个会注入到实现类的变量 hello。在下面的代码中,MyInterfaceImpl 实现了 MyInterface 接口:

public class MyInterfaceImpl implements MyInterface {
    public void sayHello() {
        System.out.println(MyInterface.hello);
    }
}

Java 中的类必须通过上述方式显式地声明实现的接口,但是在 Go 语言中实现接口使用的是隐式实现。

Go 语言中的接口

Go 语言里一个接口类型是一组方法签名的集合。一个接口类型的变量可以保存任何实现了这些方法的值。

定义接口需要使用 interface 关键字,在接口中我们只能定义方法签名,不能包含成员变量,一个常见的 Go 语言接口是这样的:

type error interface {
	Error() string
}

如果一个类型需要实现 error 接口,那么它只需要实现 Error() string 方法,下面的 RPCError 结构体就是 error 接口的一个实现:

type RPCError struct {
	Code    int64
	Message string
}

func (e *RPCError) Error() string {
	return fmt.Sprintf("%s, code=%d", e.Message, e.Code)
}

上述代码根本就没有 error 接口的影子,这是因为 Go 语言中接口的实现都是隐式的,我们只需要实现 Error() string 方法就实现了 error 接口。Go 语言实现接口的方式与 Java 完全不同:

  • 在 Java 中:实现接口需要显式地声明接口并实现所有方法;
  • 在 Go 中:实现接口的所有方法就隐式地实现了接口;

使用上述 RPCError 结构体时并不关心它实现了哪些接口,Go 语言只会在传递参数、返回值以及变量赋值时才会对某个类型是否实现接口进行检查。

func main() {
	var rpcErr error = NewRPCError(400, "unknown err") // 赋值给变量 rpcErr 时进行类型检查,看是否实现了 error 接口
	err := AsErr(rpcErr) // 给函数传递参数时进行类型检查
	println(err)
}

func NewRPCError(code int64, msg string) error {
	return &RPCError{ // 函数返回值时进行类型检查
		Code:    code,
		Message: msg,
	}
}

func AsErr(err error) error {
	return err
}

Go 语言在编译期间对代码进行类型检查,上述代码总共触发了三次类型检查。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant