向函数添加可变参数会破坏现有代码吗?
Could adding variadic parameters to a function break existing code?
向现有 Go 函数添加可变参数是否是重大更改?
例如:
// Old function
func Foo(a int)
// Updated to:
func Foo(a int, params ...string)
API 的调用者可以省略新参数,所以我认为 API 是向后兼容的。
任何人都可以提供一个示例,说明旧版 API 的用户在不更改代码的情况下无法使用新版 API 吗?
我。改变功能
调用它们将继续工作而无需修改,但由于函数签名不匹配,这可能很容易破坏一些代码。
例如(在 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
产生编译时错误:
cannot use Foo2 (type func(int, ...string)) as type func(int) in assignment
所以这是一个向后不兼容的更改,请不要这样做。
上面的例子给出了一个编译时错误,这是幸运的/更好的情况,但也可能有代码只会在运行时失败(如果/当发生这种情况时不确定),就像这个例子:
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)
会在运行时出现panic。在 Go Playground.
上试试
二.改变方法
你的问题是针对函数的,但同样的 "problem" 也存在于方法中(当用作 method expressions or method values, for example see 时)。
此外,这可能会破坏隐式接口实现(它可能会使类型不实现接口),如本示例(在 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)
向现有 Go 函数添加可变参数是否是重大更改?
例如:
// Old function
func Foo(a int)
// Updated to:
func Foo(a int, params ...string)
API 的调用者可以省略新参数,所以我认为 API 是向后兼容的。
任何人都可以提供一个示例,说明旧版 API 的用户在不更改代码的情况下无法使用新版 API 吗?
我。改变功能
调用它们将继续工作而无需修改,但由于函数签名不匹配,这可能很容易破坏一些代码。
例如(在 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
产生编译时错误:
cannot use Foo2 (type func(int, ...string)) as type func(int) in assignment
所以这是一个向后不兼容的更改,请不要这样做。
上面的例子给出了一个编译时错误,这是幸运的/更好的情况,但也可能有代码只会在运行时失败(如果/当发生这种情况时不确定),就像这个例子:
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)
会在运行时出现panic。在 Go Playground.
二.改变方法
你的问题是针对函数的,但同样的 "problem" 也存在于方法中(当用作 method expressions or method values, for example see
此外,这可能会破坏隐式接口实现(它可能会使类型不实现接口),如本示例(在 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)