Проблема с удовлетворением интерфейсу в Go
Нижеприведенный код не удовлетворяет созданному для него интерфейсу (думаю, всем понятно для чего интерфейс - DIP, модули верхнего уровня не должны зависеть от деталей и т.д.).
Ошибка при компиляции.
.\http_client_interface.go:118:13: cannot use NewClient() (type *Client) as type HTTPClient in assignment:
*Client does not implement HTTPClient (wrong type for Classic method)
have Classic() *Classic
want Classic() Requester
В упор не понимаю почему он не удовлетворяет этому интерфейсу.
Упрощенный код (именно поэтому в одном пакете - в реальности, конечно, нет), который можно запустить.
package main
import (
"bytes"
"fmt"
"io"
"time"
"net/http"
"net/url"
)
func NewClient(timeouts ...time.Duration) *Client {
timeout := 120 * time.Second
if len(timeouts) > 0 {
timeout = timeouts[0]
}
return &Client{
classic: NewClassic(timeout),
Timeout: timeout,
}
}
func NewClassic(timeouts ...time.Duration) *Classic {
timeout := 120 * time.Second
if len(timeouts) > 0 {
timeout = timeouts[0]
}
return &Classic{
Client: &http.Client{Timeout: timeout},
}
}
type Client struct {
classic *Classic
Timeout time.Duration
}
func (client *Client) SetTimeout(timeout time.Duration) {
client.Timeout = timeout
}
type Classic struct {
*http.Client
}
func (client *Client) Classic() *Classic {
return client.classic
}
func (client *Classic) SetTimeout(timeout time.Duration) {
client.Client.Timeout = timeout
}
func (client *Classic) Get(
urlPath string, queryValues url.Values, headerValues http.Header,
cookies ...*http.Cookie) *Response {
// тут много кода.... который не нужен для демонстрации
return &Response{}
}
type Response struct {
status int
err error
body []byte
}
func (r *Response) Body() []byte {
if r.body == nil {
return []byte{}
}
return r.body
}
func (r *Response) Reader() io.ReadCloser {
return io.NopCloser(bytes.NewReader(r.body))
}
func (r *Response) Error() error {
return r.err
}
func (r *Response) Status() int {
return r.status
}
//-----------------------------------------------
// интерфейс
//-----------------------------------------------
type HTTPClient interface {
SetTimeout(time.Duration)
Classic() Requester
}
type Responser interface {
Body() []byte
Reader() io.ReadCloser
Error() error
Status() int
}
type Requester interface {
SetTimeout(time.Duration)
Get(urlPath string,
query url.Values,
headers http.Header,
cookies ...*http.Cookie) Responser
}
func main(){
var client HTTPClient
client = NewClient()
fmt.Printf("%v\n", client.Classic())
}
Ответы (1 шт):
Автор решения: Pak Uula
→ Ссылка
Поменяйте сигнатуры двум методам:
func (client *Classic) Get(...)пусть возвращает не конкретный методResponse, а интерфейсResponserfunc (client *Client) Classic()пусть возвращает интерфейсRequester
После такой замены приведённая вами тестовая программа компилируется в go 1.16
package main
import (
"bytes"
"fmt"
"io"
"net/http"
"net/url"
"time"
)
func NewClient(timeouts ...time.Duration) *Client {
timeout := 120 * time.Second
if len(timeouts) > 0 {
timeout = timeouts[0]
}
return &Client{
classic: NewClassic(timeout),
Timeout: timeout,
}
}
func NewClassic(timeouts ...time.Duration) *Classic {
timeout := 120 * time.Second
if len(timeouts) > 0 {
timeout = timeouts[0]
}
return &Classic{
Client: &http.Client{Timeout: timeout},
}
}
type Client struct {
classic *Classic
Timeout time.Duration
}
func (client *Client) SetTimeout(timeout time.Duration) {
client.Timeout = timeout
}
type Classic struct {
*http.Client
}
func (client *Client) Classic() Requester {
return client.classic
}
func (client *Classic) SetTimeout(timeout time.Duration) {
client.Client.Timeout = timeout
}
func (client *Classic) Get(
urlPath string, queryValues url.Values, headerValues http.Header,
cookies ...*http.Cookie) Responser {
// тут много кода.... который не нужен для демонстрации
return &Response{}
}
type Response struct {
status int
err error
body []byte
}
func (r *Response) Body() []byte {
if r.body == nil {
return []byte{}
}
return r.body
}
func (r *Response) Reader() io.ReadCloser {
return io.NopCloser(bytes.NewReader(r.body))
}
func (r *Response) Error() error {
return r.err
}
func (r *Response) Status() int {
return r.status
}
//-----------------------------------------------
// интерфейс
//-----------------------------------------------
type HTTPClient interface {
SetTimeout(time.Duration)
Classic() Requester
}
type Responser interface {
Body() []byte
Reader() io.ReadCloser
Error() error
Status() int
}
type Requester interface {
SetTimeout(time.Duration)
Get(urlPath string,
query url.Values,
headers http.Header,
cookies ...*http.Cookie) Responser
}
func main() {
var client HTTPClient
client = NewClient()
fmt.Printf("%v\n", client.Classic())
}