在 Go 语言中,如果一个接口在一个包里,其他包要实现该接口,需要遵循下列步骤:
在青山湖等地区,都构建了全面的区域性战略布局,加强发展的系统性、市场前瞻性、产品创新能力,以专注、极致的服务理念,为客户提供成都网站建设、成都做网站 网站设计制作按需开发,公司网站建设,企业网站建设,成都品牌网站建设,成都全网营销,成都外贸网站建设公司,青山湖网站建设费用合理。
1. 定义接口:
假设接口定义在 `foo` 包中:
go
package foo
type MyInterface interface {
MyMethod() string
}
2. 实现接口:
定义一个新的类型 `Bar`,并为其实现 `foo.MyInterface` 接口:
go
package bar
import "your-package/foo"
type Bar struct {
// ...
}
func (b Bar) MyMethod() string {
// implement method
return "bar"
}
在这里,需要导入 `foo` 包,并定义一个 `Bar` 类型,为其实现 `foo.MyInterface` 接口,这样就完成了在不同包中实现接口的目标。
如果在其他包中使用 `Bar`,需要先导入 `bar` 包,然后声明 `Bar` 实例,并将其转换为 `foo.MyInterface`,然后就可以调用 `MyMethod` 方法了:
go
import "your-package/bar"
func main() {
var myInterface foo.MyInterface = new(bar.Bar)
myInterface.MyMethod()
}
在这里,我们定义了一个 `myInterface` 实例,将其类型声明为 `foo.MyInterface`,并将其初始化为 `new(bar.Bar)`。这允许我们调用 `MyMethod` 方法,这个方法实际上是由 `bar.Bar` 类型实现的。
总结起来,在其他包中使用其它包的接口,需要实现接口的包定义一个新的类型,并完成接口的实现,另一个使用接口的包需要导入实现包的路径,并将接口转换成实现类型。
1 接口的定义与理解
接口是一个自定义类型,它是一组方法的集合。从定义上来看,接口有两个特点。第一,接口本质是一种自定义类型,因此不要将golang中的接口简单理解为C++/Java中的接口,后者仅用于声明方法签名。第二,接口是一种特殊的自定义类型,其中没有数据成员,只有方法(也可以为空)。
接口是完全抽象的,因此不能将其实例化。然而,可以创建一个其类型为接口的变量,它可以被赋值为任何满足该接口类型的实际类型的值。接口的重要特性是:
(1)只要某个类型实现了接口要的方法,那么我们就说该类型实现了此接口。该类型的值可以赋给该接口的值;
(2)作为1的推论,任何类型的值都可以赋值给空接口interface{}
注意:这只是golang中接口的特性,为非所有类型的特性(接口是一种特殊的类型)。
接口的特性是golang支持鸭子类型的基础,即“如果它走起来像鸭子,叫起来像鸭子(实现了接口要的方法),它就是一只鸭子(可以被赋值给接口的值)”。凭借接口机制和鸭子类型,golang提供了一种有利于类、继承、模板之外的更加灵活强大的选择。
2 例子
type Exchanger interface {
exchange()
}
type StringPair struct {
first, second string
}
type Point[2]int
func (sp *StringPair) exchange() {
sp.first, sp.second = sp.second, sp.first
}
func (p *Point) exchange() {
p[0], p[1] = p[1], p[0]
}
func exchangeThese(exchangers ...Exchanger) {
for _, exchanger := range exchangers {
exchanger.exchange()
}
}
func main() {
pair1 := StringPair{"abc","def"}
pair2 := StringPair{"ghi","jkl"}
point := Point{5, 7}
fmt.Println(pair1, pair2, point)
pair1.exchange()
pair2.exchange()
point.exchange()
fmt.Println(pair1, pair2, point)
// exchangeThese(pair1, pair2) //wrong
exchangeThese(pair1, pair2)
fmt.Println(pair1, pair2)
}
运行结果
在本例中,自定义类型StringPair和Point指针实现了接口Exchanger所需的方法,因此该类型的值可以被赋值给接口的值。
另外,特别注意一点。如果使用exchangeThese(pair1,
pair2)会导致编译错误(如下图),正确写法应当是exchangeThese(pair1,
pair2)。这是由于真正满足接口Exchanger的类型是StringPair指针,而非StringPair。
在golang中,值接收者和指针接收者的方法集是不同的。只是golang会智能地解引用和取引用,使得二者的方法集看上去是一样的。但是,在调用exchangeThese时,就凸显出二者的不同了。
Get转到定义是如下代码,
func (c *Client) Get(url string) (resp *Response, err error) {
req, err := NewRequest("GET", url, nil)
if err != nil {
return nil, err
}
return c.Do(req)
}
看上去已经有足够多的动作了,并不是你说的只是一个接口啊
golang语言本身就是c的工具集,开发c的程序用到的大部分结构体,内存管理,携程等,golang基本都有,他只是在这个基础上又加了一些概念这里说一个很小的问题,就是字节数组转string的问题,网上大部分都是这样转的(包括google上):string(p[:]),这个转完了是有问题的,我们再来看一下string这个结构体:
struct String
{
byte* str;
intgo len;
};
这个结构体让我想起了nginx的string,他是这样定义的:
typedef struct {
size_t len;
u_char *data;
} ngx_str_t;
golang里边 string的概念其实不是以前遇到\0结尾的概念了,他其实就是一块连续的内存,首地址+长度,上面那样赋值,如果p里边有\0,他不会做处理这个时候,如果再对这个string做其他处理就可能出问题了,比如strconv.Atoi转成int就有错误,解决办法就是需要自己写一个正规的转换函数:
func byteString(p []byte) string {
for i := 0; i len(p); i++ {
if p[i] == 0 {
return string(p[0:i])
}
}
return string(p)
}
这样就不会出问题了