根据条件选择包装

We have 2 packages that implement the same function signatures. In my main I need to switch out the package being used based on a condition:

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

someCondition := true
var packageToUse ?

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

packageToUse.DoSomething()

Of course, this doesn't compile. I don't know what type to use for packageToUse. This approach is probably an anti-pattern. I'm just not sure the approach I should be taking.

any suggestions?

The error I get is use of package without selector

This isn't quite what you asked, but this is how I would accomplish the goal if I were you:

// 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()

Following up a bit on comment about using an interface

I would step back a bit and see if this can be better solved using an interface that you provide the concrete class for in the condition statement.

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()
}

It is very much a pattern - aside from the dynamic import. It is called „Interfaces“.

Given an interface definition like

type Stringer interface{
  String() string
}

and the type Foo implementing said interface

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

as well as Bar implementing said interface

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

one can actually use both as a parameter for a function baz

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

Note that unlike other languages, you do not have to declare the interfaces a type implements - as long as a type happens to factually implement an interface, the go compiler is ok with it. Run on Playground

So, with regards to your question of package imports: Unless you have ginormous dependency trees to import, it really is not worth the hassle.

Say we talk of an application using either BBolt or etcd and for good measure some MongoDB. The resulting size to include all of them, while relatively speaking is quite astonishing, is negligible. I compiled a go program with imports of bbolt, bbolt & etcd and bbolt, etcd & mongodb. These are the results in bytes.

11734884  size_all 
2455544   size_bolt
10307700  size_boltetcd

We are talking of a few megabytes in file size. So say you use either Bolt or etcd or MongoDB, do you really want to jump through all the hoops and loops required to get dynamic imports done properly? I for my part would neither want to do it nor would I want Go to provide such a feature.

"Premature optimization is the root of all evil (or at least most of it) in programming."

– Donald Knuth