Может ли добавление переменных параметров в функцию нарушить существующий код? - PullRequest
7 голосов
/ 14 марта 2019

Является ли добавление параметра variadic в существующую функцию Go серьезным изменением?

Например:

// Old function
func Foo(a int)

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

Призыватели API могут опустить новый параметр, поэтому я думаю, что API обратно совместим.

Может ли кто-нибудь привести пример, когда пользователь старого API не мог использовать новый API без изменения своего кода?

1 Ответ

11 голосов
/ 14 марта 2019

I.Изменение функций

Вызов их будет продолжать работать без изменений, но поскольку сигнатуры функций не совпадают, это может легко привести к поломке некоторого кода.

Например (попробуйте на GoДетская площадка ):

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 .

II.Изменение методов

Ваш вопрос был направлен на функции, но та же «проблема» существует и с методами (при использовании в качестве выражений методов или значений методов , например, см. golang - передать метод в функцию ).

Кроме того, это может нарушить неявные реализации интерфейса (это может привести к тому, что типы не будут реализовывать интерфейсы), как в этом примере (попробуйте на 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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...