Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/go/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/neo4j/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
golang API接口,我缺少什么?_Go_Interface - Fatal编程技术网

golang API接口,我缺少什么?

golang API接口,我缺少什么?,go,interface,Go,Interface,我想创建一个界面,以便于添加新的存储后端 package main // Storage is an interface to describe storage backends type Storage interface { New() (newStorage Storage) } // File is a type of storage that satisfies the interface Storage type File struct { } // New retur

我想创建一个界面,以便于添加新的存储后端

package main

// Storage is an interface to describe storage backends
type Storage interface {
    New() (newStorage Storage)
}

// File is a type of storage that satisfies the interface Storage
type File struct {
}

// New returns a new File
func (File) New() (newFile Storage) {
    newFile = File{}
    return newFile
}

// S3 is a type of storage that satisfies the interface Storage
type S3 struct {
}

// New returns a new S3
func (S3) New() (newS3 S3) {
    newS3 = S3{}
    return newS3
}

func main() {
    // List of backends to choose from
    var myStorage map[string]Storage
    myStorage["file"] = File{}
    myStorage["s3"] = S3{}

    // Using one of the backends on demand
    myStorage["file"].New()
    myStorage["s3"].New()
}
但是,似乎不可能定义并满足一个函数,该函数应该返回一个同样满足接口本身的对象

File.New()返回满足存储要求的存储类型的对象

New()返回一个S3类型的对象。 S3也应该满足接口存储的要求,但我知道:

./main.go:32: cannot use S3 literal (type S3) as type Storage in assignment:
    S3 does not implement Storage (wrong type for New method)
        have New() S3
        want New() Storage
我做错了什么?
我希望我在这里遗漏了一些基本的东西。

我喜欢你在这里所做的工作,而且我实际上参与过一些涉及非常相似的设计挑战的项目,所以我希望我的建议可以帮助你解决一些问题

为了满足接口的要求,您需要从

// New returns a new S3
func (S3) New() (newS3 S3) {
    newS3 = S3{}
    return newS3
}
对此

// New returns a new S3
func (S3) New() (newS3 Storage) {
    newS3 = S3{}
    return newS3
}
这意味着您将收到一个存储实例。如果您希望在不使用的情况下访问S3中的任何内容,最好在接口中公开S3函数/方法

假设您想要一种在S3客户机中列出对象的方法。支持这一点的一个好方法是更新存储接口以包含列表,并更新S3以使其具有自己的列表实现:

// Storage is an interface to describe storage backends
type Storage interface {
    New() (newStorage Storage)
    List() ([]entry, error) // or however you would prefer to trigger List
}

...

// New returns a new S3
func (S3) List() ([] entry, error) {
    // initialize "entry" slice
    // do work, looping through pages or something
    // return entry slice and error if one exists
}
当需要添加对Google云存储、Rackspace云文件、Backblaze B2或任何其他对象存储提供程序的支持时,它们中的每一个还需要实现List()([]条目,错误)-这很好!一旦您以您需要的方式使用了这个列表函数,添加更多的客户机/提供者将更像是开发插件,而不是实际编写/架构代码(因为您的设计已经完成了)

具有令人满意的接口的真正关键是使签名完全匹配,并将接口视为您希望每种存储提供程序类型都能处理的常见函数/方法的列表,以满足您的目标


如果您有任何问题,或者我写的任何东西不清楚,请发表评论,我很乐意澄清或调整我的帖子:)

我喜欢您在这里所做的工作,并且我实际参与过涉及非常相似的设计挑战的项目,因此我希望我的建议可以帮助您解决一些问题

为了满足接口的要求,您需要从

// New returns a new S3
func (S3) New() (newS3 S3) {
    newS3 = S3{}
    return newS3
}
对此

// New returns a new S3
func (S3) New() (newS3 Storage) {
    newS3 = S3{}
    return newS3
}
这意味着您将收到一个存储实例。如果您希望在不使用的情况下访问S3中的任何内容,最好在接口中公开S3函数/方法

假设您想要一种在S3客户机中列出对象的方法。支持这一点的一个好方法是更新存储接口以包含列表,并更新S3以使其具有自己的列表实现:

// Storage is an interface to describe storage backends
type Storage interface {
    New() (newStorage Storage)
    List() ([]entry, error) // or however you would prefer to trigger List
}

...

// New returns a new S3
func (S3) List() ([] entry, error) {
    // initialize "entry" slice
    // do work, looping through pages or something
    // return entry slice and error if one exists
}
当需要添加对Google云存储、Rackspace云文件、Backblaze B2或任何其他对象存储提供程序的支持时,它们中的每一个还需要实现List()([]条目,错误)-这很好!一旦您以您需要的方式使用了这个列表函数,添加更多的客户机/提供者将更像是开发插件,而不是实际编写/架构代码(因为您的设计已经完成了)

具有令人满意的接口的真正关键是使签名完全匹配,并将接口视为您希望每种存储提供程序类型都能处理的常见函数/方法的列表,以满足您的目标


如果您有任何问题或我写的任何东西不清楚,请发表评论,我很乐意澄清或调整我的帖子:)

此代码毫无意义。您要么正在实现一个绑定到工厂将要生产的结构类型的工厂模式,要么正在以错误的方式重新创建轮子,方法是重新实现已经存在的关键字,并将其绑定到一个在您使用它时为
nil
的结构

您可以去掉helper函数,只需使用

s := new(S3)
f := new (File)
或者您可以使用静态工厂功能,如:

// Do NOT tie your Factory to your type
function New() S3 {
  return S3{}
}
或者,更适合您的用例,创建一个工厂接口,实现它并让它的
New()
函数返回一个
Storage
实例:

type StorageFactory interface {
  New() Storage
}

type S3Factory struct {}

function (f *S3Factory) New() Storage {
  return S3{}
}
注册工厂有多种方式。可以使用全局变量和init

import "example.com/foo/storage/s3"

type FactoryGetter func() StorageFactory
type FactoryRegistry map[string] FactoryGetter

// Registry will be updated by an init function in the storage provider packages
var Registry FactoryRegistry

func init(){
  Registry = make(map[string] FactoryGetter)
}

// For the sake of shortness, a const. Make it abflag, for example
const storageProvider = "s3"

func main(){
  f := Registry[storageProvider]()
  s := f.New()
  s.List()
}
在S3包的某个地方

func init() {
  Registry["s3"] = function(){ return S3Factory{}}
}

你甚至可以考虑让工厂采用params

这段代码毫无意义。您要么正在实现一个绑定到工厂将要生产的结构类型的工厂模式,要么正在以错误的方式重新创建轮子,方法是重新实现已经存在的关键字,并将其绑定到一个在您使用它时为
nil
的结构

您可以去掉helper函数,只需使用

s := new(S3)
f := new (File)
或者您可以使用静态工厂功能,如:

// Do NOT tie your Factory to your type
function New() S3 {
  return S3{}
}
或者,更适合您的用例,创建一个工厂接口,实现它并让它的
New()
函数返回一个
Storage
实例:

type StorageFactory interface {
  New() Storage
}

type S3Factory struct {}

function (f *S3Factory) New() Storage {
  return S3{}
}
注册工厂有多种方式。可以使用全局变量和init

import "example.com/foo/storage/s3"

type FactoryGetter func() StorageFactory
type FactoryRegistry map[string] FactoryGetter

// Registry will be updated by an init function in the storage provider packages
var Registry FactoryRegistry

func init(){
  Registry = make(map[string] FactoryGetter)
}

// For the sake of shortness, a const. Make it abflag, for example
const storageProvider = "s3"

func main(){
  f := Registry[storageProvider]()
  s := f.New()
  s.List()
}
在S3包的某个地方

func init() {
  Registry["s3"] = function(){ return S3Factory{}}
}

你甚至可以考虑让工厂采用params

S3结构和文件结构有不同的返回obj类型,尝试使用接口作为返回,使两者返回相同类型的obj。当返回结构作为接口时,不要忘记使用指针。Go没有协方差。@Kebeng我不介意在这里获取对象的副本,因此不需要指针。这里的重点是将它们设置为“相同类型”。S3结构和文件结构具有不同的返回obj类型,请尝试使用接口作为返回,使它们都返回相同类型的obj。当返回结构作为接口时,不要忘记使用指针。Go没有协方差。@Kebeng我不介意在这里获取对象的副本,因此不需要指针。让它们成为“同一类型”是这里的重点。