向函数添加可变参数会破坏现有代码吗?

时间:2019-03-14 12:49:51

标签: go parameters variadic-functions backwards-compatibility

向现有的Go函数添加可变参数是一项重大更改吗?

例如:

df.withColumn("colname", from_json($"colname", schema))
df.selectExpr("split(substring()))

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

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

1 个答案:

答案 0 :(得分: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)类型

这是向后不兼容的更改,请不要这样做。

上面的示例给出了一个编译时错误,这是幸运的/更好的情况,但是也可能有一些代码仅在运行时失败(如果/发生,则是不确定的),例如此示例:< / p>

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)