可以在函数中添加可变参数来破坏现有代码吗?

问题描述 投票:7回答:1

在现有的Go函数中添加一个可变参数是一个重大改变吗?

例如:

// Old function
func Foo(a int)

// Updated to:
func Foo(a int, params ...string)

API的调用者可以省略新参数,因此我认为API是向后兼容的。

任何人都可以提供一个示例,其中旧API的用户无法在不更改其代码的情况下使用新API吗?

go parameters variadic-functions backwards-compatibility
1个回答
11
投票

I.改变职能

调用它们将继续工作而不进行修改,但由于函数签名不匹配,这可能很容易破坏某些代码。

例如(在Go Playground上试试):

func Foo(a int)                    {}
func Foo2(a int, params ...string) {}

func main() {
    var f func(int)

    f = Foo
    f = Foo2 // Compile-time error!

    _ = f
}

f = Foo2产生编译时错误:

不能在赋值中使用Foo2(类型为func(int,... string))作为类型func(int)

所以这是一个向后不兼容的变化,不要这样做。

上面的例子给出了一个编译时错误,这是幸运/更好的情况,但也可能有代码只会在运行时失败(如果/当发生时会发生非确定性),如下例所示:

func Foo(a int)                    {}
func Foo2(a int, params ...string) {}

func main() {
    process(Foo)
    process(Foo2) // This will panic at runtime (type assertion will not hold)!
}

func process(f interface{}) {
    f.(func(int))(1)
}

调用process(foo)成功,调用process(foo2)将在运行时恐慌。在Go Playground上尝试一下。

II。改变方法

你的问题是针对函数的,但是方法也存在同样的“问题”(当用作method expressionsmethod values时,例如参见golang - pass method to function)。

另外,这可能会破坏隐式接口实现(它可能使类型不实现接口),就像在这个例子中一样(在Go Playground上试试):

type Fooer interface {
    Foo(int)
}

type fooImpl int

func (fooImpl) Foo(a int) {}

type fooImpl2 int

func (fooImpl2) Foo(a int, params ...string) {}

func main() {
    var f Fooer

    f = fooImpl(0)
    f = fooImpl2(0) // Compile time error!

    _ = f
}

因为签名不匹配,fooImpl2没有实现Fooer,即使fooImpl

cannot use fooImpl2(0) (type fooImpl2) as type Fooer in assignment:
  fooImpl2 does not implement Fooer (wrong type for Foo method)
      have Foo(int, ...string)
      want Foo(int)
© www.soinside.com 2019 - 2024. All rights reserved.