小梅子 發表於 2024-2-14 17:15:00

Go 之烧脑的接口

<h2>基本定义</h2>
<p>Go 官方对于接口的定义是一句话:An&nbsp;<em>interface type</em> is defined as a set of method signatures. 翻译过来就是,一个接口定义了一组方法的集合。这和 Java 和 PHP 的接口类似,定义一组方法而不定义方法的具体实现。但是与 Java 和 PHP 迥然不同的地方在于 Go 不需要显式的声明 <code>implements</code> 关键词来继承接口,一个类型只要实现了接口中的所有方法,就视作继承了该接口,是隐式实现的。来看一个基本的使用示例:&nbsp;</p>
<pre class="language-markup highlighter-hljs"><code>// 定义一个平台接口,包含一个支付方法
type Platform interface {
        Pay(amount int) error
}

// 微信平台
type Wechat struct{}

func (w *Wechat) Pay(amount int) error {
        fmt.Printf("wechat amount: %d\n", amount)
        return nil
}

// 支付宝平台
// 任意值都可以实现接口,并非一定需要struct
type Alipay int

func (a Alipay) Pay(amount int) error {
        fmt.Printf("alipay amount: %d, a: %d\n", amount, a)
        return nil
}

func ExamplePlatform() {
        var (
                p Platform
                w      = Wechat{}
                a Alipay = 1
        )
        p = &amp;w
        p.Pay(2)

        p = &amp;a
        p.Pay(3)

        // 这种写法会报错
        // p = w
        p = a
        p.Pay(4)

        // Output:
        // wechat amount: 2
        // alipay amount: 3, a: 1
        // alipay amount: 4, a: 1
}</code></pre>
<p>在这个示例中,我们定义了一个&nbsp;<code>Platform</code> 接口和两个结构体,分别使用了值接收器和指针接收器来实现了 <code>Platform</code> 接口。<code>p = w</code> 这行代码会报错,究其原因是,对于使用指针接收器实现的接口的 <code>Wechat</code>,只有它的<strong>指针会实现接口,值不会实现</strong>;而对于值实现接口的&nbsp;<code>Alipay</code>,指针和值都会实现接口。所以 <code>p = a</code> 可以正常运行。</p>
<h2>接口嵌套</h2>
<p>接口可以嵌套另一个接口:</p>
<pre class="language-markup highlighter-hljs"><code>// 定义一个平台接口,包含一个支付方法
type Platform interface {
        Pay(amount int) error
        User
}

type User interface {
        Login()
        Logout()
}

// 微信平台
type Wechat struct{}

func (w *Wechat) Pay(amount int) error {
        fmt.Printf("wechat amount: %d\n", amount)
        return nil
}

func (w *Wechat) Login(){}
func (w *Wechat) Logout() {}</code></pre>
<p>此时,<code>Wechat</code> 即实现了 <code>Platform</code> 接口,也实现了&nbsp;<code>User</code> 接口。</p>
<h2>接口类型断言</h2>
<p>再来看一个很复杂的例子,我们将上面的代码稍作修改,将 <code>Wechat</code> 的 <code>Login</code> 和<code> Logout</code> 提到另一个结构中,然后使用类型断言判断 <code>Wechat</code> 是否实现了 <code>User</code> 接口:</p>
<pre class="language-markup highlighter-hljs"><code>// 定义一个平台接口,包含一个支付方法
type Platform interface {
        Pay(amount int) error
        User
}

type User interface {
        Login()
        Logout()
}

type UserS struct {
}

func (u *UserS) Login(){}
func (u *UserS) Logout() {}

// 微信平台
type Wechat struct {
        UserS
}

func (w *Wechat) Pay(amount int) error {
        fmt.Printf("wechat amount: %d\n", amount)
        return nil
}

func ExamplePlatform() {
        var (
                p Platform
                w = Wechat{}
        )
        p = &amp;w
        p.Pay(2)

        // 类型断言
        _, ok := p.(User)
        fmt.Println(ok)

        // Output:
        // wechat amount: 2
        // true
}</code></pre>
<h2>空接口</h2>
<p>Go 1.18 新增了一个新的变量类型:<code>any</code>,其定义如下:</p>
<pre class="language-markup highlighter-hljs"><code>type any = interface{}</code></pre>
<p>其实 any 就是一个空接口,对于空接口而言,它没有任何方法,所以对于任意类型的值都相当于实现了空接口,这个概念和另一个编程概念十分相似,它就是大名鼎鼎的泛型。在 Go 语言中,<code>fmt.Println</code> 函数的接收值正是一个 <code>any</code>:</p>
<pre class="language-markup highlighter-hljs"><code>func Println(a ...any) (n int, err error) {
        return Fprintln(os.Stdout, a...)
}</code></pre>
<p>使用空接口搭配类型断言,我们可以设计出一个简单的类型转换函数,它将任意类型的值转为 int:</p>
<pre class="language-markup highlighter-hljs"><code>func ToInt(i any) int {
        switch v := i.(type) {
        case int:
                return v
        case float64:
                return int(v)
        case bool:
                if v {
                        return 1
                }
                return 0
        case string:
                vint, _ := strconv.Atoi(v)
                return vint
        }

        return 0
}</code></pre><br><br>
来源:https://www.cnblogs.com/oldme/p/18015328
頁: [1]
查看完整版本: Go 之烧脑的接口