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.Book的Pages()方法返回的是[]novel.Page,而novelapp.BookInterface要求Pages()返回[]novelapp.PageInterface。虽然novel.Page实现了novelapp.PageInterface,但Go语言的类型系统不会自动将[]novel.Page转换为[]novelapp.PageInterface。
解决方案是修改novel.Book的Pages()方法,使其返回接口切片。以下是修改后的代码:
// 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)
}
关键修改:
- 在
novel包中定义PageInterface接口 Book结构体的pages字段改为[]PageInterface类型Pages()方法返回[]PageInterface类型- 在
NewBook函数中,将[]Page转换为[]PageInterface
这样novel.Book就完全实现了novelapp.BookInterface接口,同时保持了包之间的解耦。

