Перейти пакет выбора в зависимости от условия - PullRequest
1 голос
/ 28 июня 2019

У нас есть 2 пакета, которые реализуют одинаковые сигнатуры функций. В моем основном я должен выключить используемый пакет на основе условия:

    import (
packageA "deployment/sdk/packageA"
packageB "deployment/sdk/packageB"
)

someCondition := true
var packageToUse ?

if someCondition {
    packageToUse = packageA
} else {
    packageToUse = packageB
}

packageToUse.DoSomething()

Конечно, это не компилируется. Я не знаю, какой тип использовать для packageToUse. Этот подход, вероятно, является анти-паттерном. Я просто не уверен, какой подход мне следует использовать.

есть предложения?

Я получаю ошибку use of package without selector

Ответы [ 3 ]

4 голосов
/ 28 июня 2019

Это очень похоже на шаблон - кроме динамического импорта. Он называется «Интерфейсы» .

Учитывая определение интерфейса как

type Stringer interface{
  String() string
}

и тип Foo, реализующий указанный интерфейс

type foo int
func(f foo)String() string{
  return fmt.Sprintf(”%d”,f)
}

, а также Bar, реализующий указанный интерфейс

type bar string
func (b bar) String()string {
  return string(b)
}

Фактически можно использовать оба в качестве параметра для функции baz

func baz(s Stringer){
  fmt.Println(s.String())
}

Обратите внимание, что в отличие от других языков, вам не нужно объявлять интерфейсы, которые реализует тип, - если тип фактически реализует интерфейс, компилятор go с ним согласен. Бег на детской площадке

Итак, что касается вашего вопроса об импорте пакетов: если у вас нет огромных деревьев зависимостей для импорта, это действительно не стоит хлопот.

Допустим, мы говорим о приложении, использующем либо BBolt, либо etcd, а в качестве примера - MongoDB. Результирующий размер, включающий всех из них, хотя, говоря относительно, весьма удивителен, незначителен. Я скомпилировал программу go с импортом bbolt, bbolt & etcd и bbolt, etcd & mongodb. Это результаты в байтах.

11734884  size_all 
2455544   size_bolt
10307700  size_boltetcd

Мы говорим о нескольких мегабайтах в размере файла. Допустим, вы используете либо Bolt , либо etcd , либо MongoDB, хотите ли вы действительно прыгать через все обручи и циклы, необходимые для правильного выполнения динамического импорта? Я, со своей стороны, не хотел бы этого делать и не хотел бы, чтобы Go предоставил такую ​​функцию.

«Преждевременная оптимизация - корень всего зла (или, по крайней мере, большей его части) в программировании».

& Ndash; Дональд Кнут

3 голосов
/ 28 июня 2019

Это не совсем то, что вы просили, но вот как бы я достиг цели на вашем месте:

// I assumed both package functions have the same signature, so you can use a type
// TODO: Actual function signature you want to use here
type myFn func() error

var fnToUse myFn
if someCondition {
    fnToUse = packageA.Func1
} else {
    fnToUse = packageB.Func2
}

fnToUse()
0 голосов
/ 28 июня 2019

После комментария об использовании интерфейса

Я бы немного отступил и посмотрел, можно ли решить эту проблему лучше, используя интерфейс, для которого вы предоставляете конкретный класс в условии заявление.

package packageA 

type Thing struct {

}

func (t Thing) DoSomething() {
}

-

package packageB

type Thing struct {

}

func (t Thing) DoSomething() {
}

-

package main 

import (
  "packageA"
  "packageB"
)

type PackageUser interface {
  DoSomething()
}

func main() {
  var pu PackageUser 
  if (condition) {
    pu := packageA.Thing{}
  } else {
    pu := packageB.Thing{}
  }
  pu.DoSomething()
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...