Golang中从类型返回值的隐式接口问题探讨

Golang中从类型返回值的隐式接口问题探讨 Go语言格言说:“接受接口,返回结构体”。我想将novelapp包(消费者)与novel包(提供者)解耦,并通过接口使用novel而无需导入。这对于具有Title函数的Book接口有效,但我无法用PageInterface替换Page……为什么不行?

我想要实现的是能够几乎彼此独立地插入任何包,并使用main来将这些部分组合在一起。

示例代码:

// package novel
package novel

// Page ...
type Page struct {
    title string
}

func NewPage(title string) Page {
    return Page{title: title}
}

// Title ...
func (p *Page) Title() string {
    return p.title
}

// Book ...
type Book struct {
    title string
    pages []Page
}

func NewBook(title string, pages []Page) *Book {
    return &Book{title: title, pages: pages}
}

// Title ...
func (b *Book) Title() string {
    return b.title
}

// Pages ...
func (b *Book) Pages() []Page {
    return b.pages
}
// package novelapp
package novelapp

import "fmt"

// BookInterface ...
type BookInterface interface {
    Title() string

    Pages() []PageInterface
}

// PageInterface ...
type PageInterface interface {
    Title() string
}

// PrintBook ...
func PrintBook(book BookInterface) {
    fmt.Println(book.Title())
}
// package main
package main

import (
    "sandbox/pkg/novel"
    "sandbox/pkg/novelapp"
)

func main() {
    book := novel.NewBook("Book Title", []novel.Page{novel.NewPage("Page Title")})
    novelapp.PrintBook(book)
}
.\main.go:10:20: cannot use book (type *novel.Book) as type novelapp.BookInterface in argument to novelapp.PrintBook:
        *novel.Book does not implement novelapp.BookInterface (wrong type for Pages method)
                have Pages() []novel.Page
                want Pages() []novelapp.PageInterface

更多关于Golang中从类型返回值的隐式接口问题探讨的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于Golang中从类型返回值的隐式接口问题探讨的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


问题在于novel.BookPages()方法返回的是[]novel.Page,而novelapp.BookInterface要求Pages()返回[]novelapp.PageInterface。虽然novel.Page实现了novelapp.PageInterface,但Go语言的类型系统不会自动将[]novel.Page转换为[]novelapp.PageInterface

解决方案是修改novel.BookPages()方法,使其返回接口切片。以下是修改后的代码:

// package novel
package novel

// PageInterface 在novel包中定义相同的接口
type PageInterface interface {
    Title() string
}

// Page ...
type Page struct {
    title string
}

func NewPage(title string) Page {
    return Page{title: title}
}

// Title ...
func (p *Page) Title() string {
    return p.title
}

// Book ...
type Book struct {
    title string
    pages []PageInterface  // 改为接口类型
}

func NewBook(title string, pages []Page) *Book {
    // 将[]Page转换为[]PageInterface
    pageInterfaces := make([]PageInterface, len(pages))
    for i, page := range pages {
        pageInterfaces[i] = &page
    }
    return &Book{title: title, pages: pageInterfaces}
}

// Title ...
func (b *Book) Title() string {
    return b.title
}

// Pages ...
func (b *Book) Pages() []PageInterface {  // 返回接口切片
    return b.pages
}
// package novelapp
package novelapp

import "fmt"

// BookInterface ...
type BookInterface interface {
    Title() string
    Pages() []PageInterface
}

// PageInterface ...
type PageInterface interface {
    Title() string
}

// PrintBook ...
func PrintBook(book BookInterface) {
    fmt.Println(book.Title())
    for _, page := range book.Pages() {
        fmt.Println("  -", page.Title())
    }
}
// package main
package main

import (
    "sandbox/pkg/novel"
    "sandbox/pkg/novelapp"
)

func main() {
    book := novel.NewBook("Book Title", []novel.Page{
        novel.NewPage("Page 1"),
        novel.NewPage("Page 2"),
    })
    novelapp.PrintBook(book)
}

关键修改:

  1. novel包中定义PageInterface接口
  2. Book结构体的pages字段改为[]PageInterface类型
  3. Pages()方法返回[]PageInterface类型
  4. NewBook函数中,将[]Page转换为[]PageInterface

这样novel.Book就完全实现了novelapp.BookInterface接口,同时保持了包之间的解耦。

回到顶部