Go 使用不同级别的接口

Go 使用不同级别的接口,go,interface,Go,Interface,我正试图使用Go中的接口来组织代码 我有两个数据源:FTP和API。在每个源代码中,我都有几个结构,使逻辑根据情况而变化 在这个问题上,我将省略API并坚持使用FTP 我的问题来自于无法说:FTPAcq也是一项收购 如果FetchMeters(),当我执行ftp.Decrypt(nil)时,我希望ftp与FTPAcq“兼容” 这是我的密码: package main import ( "github.com/dutchcoders/goftp" log "github.com/

我正试图使用Go中的接口来组织代码

我有两个数据源:FTP和API。在每个源代码中,我都有几个结构,使逻辑根据情况而变化

在这个问题上,我将省略API并坚持使用FTP

我的问题来自于无法说:FTPAcq也是一项收购

如果
FetchMeters()
,当我执行
ftp.Decrypt(nil)
时,我希望ftp与
FTPAcq“兼容”

这是我的密码:

package main

import (
    "github.com/dutchcoders/goftp"
    log "github.com/sirupsen/logrus"
    "os"
)

type Acquisition interface {
    FetchMeters() ([]Meter, error)
    Name() string
}

type FTPAcq interface {
    Unzip(file string) string
    Decrypt(file string) string
}

//type APIAcq interface {
//  FetchMeter(meterID string) (Meter, error)
//}

func main() {
    var acqs []Acquisition
    ftp, err := NewFTPDriver(os.Getenv("FTP_USER"), os.Getenv("FTP_PASSWD"), os.Getenv("FTP_ADDR"), os.Getenv("FTP_PORT"))
    if err != nil {
        panic(err)
    }
    ftp1 := NewFTPDriverSGE(*ftp)
    ftp2 := NewFTPDriverTA(*ftp)
    acqs = append(acqs, ftp1, ftp2)
    for _, acq := range acqs {
        tmpMeters, err := acq.FetchMeters()
        if err != nil {
            log.Warn(acq.Name(), " got error :", err)
        }
        log.Info(tmpMeters)
    }
}

type Meter struct {
    ID          string
    OperationID string
    Unit        string
}

//FtpSGE is a implementation of acquisition Interface (see driver.go)
type FTP struct {
    Username string
    Password string
    Url      string
    Port     string
    client   *goftp.FTP
}
type FTPSGE struct {
    FTP
}
type FTPTA struct {
    FTP
}

func (f FTPSGE) Unzip(path string) []string {
    return nil
}
func (f FTPTA) Unzip(path string) []string {
    return nil
}

func (f FTPSGE) Decrypt(path string) []string {
    return nil
}

func (f FTPTA) Decrypt(path string) []string {
    return nil
}

func (ftp FTP) FetchMeters() ([]Meter, error) {
    log.Info(ftp.Name(), " is running")
    files := ftp.Download(nil)
    files = ftp.Decrypt("") // I have several implementation of Decrypt
    files = ftp.Unzip("")   // I have several implementation of Unzip
    log.Info(files)
    return nil, nil
}

func (ftp FTP) Name() string {
    panic("FTP ")
}

func (ftp FTP) Download(files []string) []string {
    panic("implement me")
}

func NewFTPDriver(user, password, url, port string) (*FTP, error) {
    var err error
    ftp := &FTP{
        Username: user,
        Password: password,
        Url:      url,
        Port:     port,
    }
    if ftp.client, err = goftp.Connect(url + ":" + port); err != nil {
        return nil, err
    }
    if err = ftp.client.Login(user, password); err != nil {
        return nil, err
    }
    return ftp, nil
}
func NewFTPDriverSGE(f FTP) *FTPSGE {
    return &FTPSGE{f}
}

func NewFTPDriverTA(f FTP) *FTPTA {
    return &FTPTA{f}
}
就我而言,我得到:

ftp.Decrypt undefined (type FTP has no field or method Decrypt)

我该怎么办?

FTP
是否执行
FTPAcq
。它只实现
采集
。它甚至没有
Decrypt()
作为方法、接口或非接口

FTPSGE
FTPTA
实现
FTPAcq
,但它们与
FTP
的类型不同

我不知道你想做什么,但也许可以尝试在
FTPSGE
FTPTA
中嵌入
FTP
。这为这两种类型提供了嵌入类型的字段和方法,并且仍然允许您在这些类型上定义其他方法(在您的案例中为
FTPAcq
定义的方法)

比如说

类型FTPSGE{
文件传输协议
}
//或
类型FTPSGE{
*FTP
}
然后将其创建为:
x:=FTPSGE{ftp1}
。请记住,这将在
x
内部创建
ftp1
副本。如果
ftp1
类型为
FTP
(不是指针),则复制整个结构。如果
ftp1
类型为
*FTP
(一个指针,似乎就是您正在使用的),则会复制指针,并且
x.FTP
仍然指向与
ftp1
相同的数据

这意味着
FTPSGE
将实现
采集
FTPAcq

您必须注意是否在值或指针上实现了接口:
func(a)Something()
vs
func(a*a)Somthing()

下面是一些关于方法、接口和嵌入的阅读

  • (还有很多其他信息)

  • 您试图对一个没有该方法的类型调用
    Decrypt
    。只能对实际具有这些方法的类型的值调用方法。请注意,这与接口无关。您可以同时删除它们,但仍然会得到相同的错误。