Go - Using Multiple Versions of the Same Dependent Packages

发布时间 2023-09-29 09:25:29作者: ZhangZhihuiAAA

Problem: You want to use multiple versions of the same dependent packages in your code.


Solution: Use the replace directive in the go.mod file to rename your package.

Though it might seem like a very niche requirement, there is sometimes a need to be able to use multiple versions of the same package in your project. In the previous recipe, we talked about one possible use — if you want to migrate a large codebase incrementally but still enable it to work while you’re migrating, you might want to use different versions of the same package.
Another possible reason is when you have a dependent package that works only with a specific version of another package. This is more common than you might think because packages developed by different developers move according to their project schedules. You could be in trouble if one of your critical dependent packages still uses an older version of a shared dependent package.
Semantic import versions work well because the major versions require a change in the path. However, this wouldn’t work in the case of minor version upgrades. In this case, you can use the replace directive to rename a package and use the new name to import it into your code.


First, change the go.mod file to rename your packages. Say you’re using both v1.8.0 and v1.7.4 for gorilla/mux .
You rename these packages accordingly using the replace directive:

go 1.20

replace github.com/gorilla/mux/180 => github.com/gorilla/mux v1.8.0
replace github.com/gorilla/mux/174 => github.com/gorilla/mux v1.7.4

Run go get to get the package versions using their new names:

$ go get github.com/gorilla/mux/174
$ go get github.com/gorilla/mux/180

If you open your go.mod , you should see the two new packages being required:

go 1.20

replace github.com/gorilla/mux/180 => github.com/gorilla/mux v1.8.0
replace github.com/gorilla/mux/174 => github.com/gorilla/mux v1.7.4

require (
    github.com/gorilla/mux/174 v0.0.0 - 00010101000000 - 000000000000 // indirect
    github.com/gorilla/mux/180 v0.0.0 - 00010101000000 - 000000000000 // indirect
)

Now you can go back to your code and import these two packages:

package   main 

import   ( 
      "log" 
      "net/http" 
      "text/template" 

      mux174   "github.com/gorilla/mux/174" 
      mux180   "github.com/gorilla/mux/180" 
) 

func   main ()   { 
      r   :=   mux180 . NewRouter () 
      r . HandleFunc ( "/{text}" ,   name ) 
      log . Fatal ( http . ListenAndServe ( ":8080" ,   r )) 
} 

func   name ( w   http . ResponseWriter ,   r   * http . Request )   { 
      vars   :=   mux174 . Vars ( r ) 
      t ,   _   :=   template . ParseFiles ( "static/text.html" ) 
      t . Execute ( w ,   vars [ "text" ]) 
}

Note that while this program builds and runs because you are using two separate packages, the mux174.Vars will not be able to get the path from the URL.
What happens if you vendor the packages now?
Run go mod vendor from the command line. Now open your vendor package. You should be able to see two different versions of the package under two different directories as if they are different packages altogether.