content: use tabs consistently for code blocks + indentation
A few articles used four spaces instead.
The present format will convert to four spaces for indentation on its own; use tabs.
The present format does not care what indentation is used, but use tabs everywhere for consistency.
For golang/go#33955.
Change-Id: I2bab8aa72fa2f68d48fb833b7317f87d7624a05f
Reviewed-on: https://go-review.googlesource.com/c/blog/+/222840
Reviewed-by: Ian Lance Taylor <iant@golang.org>
diff --git a/content/a-new-go-api-for-protocol-buffers.article b/content/a-new-go-api-for-protocol-buffers.article
index 5230db7..f3afe0a 100644
--- a/content/a-new-go-api-for-protocol-buffers.article
+++ b/content/a-new-go-api-for-protocol-buffers.article
@@ -69,35 +69,35 @@
type so we can annotate fields as containing
sensitive information or not.
- syntax = "proto3";
- import "google/protobuf/descriptor.proto";
- package golang.example.policy;
- extend google.protobuf.FieldOptions {
- bool non_sensitive = 50000;
- }
+ syntax = "proto3";
+ import "google/protobuf/descriptor.proto";
+ package golang.example.policy;
+ extend google.protobuf.FieldOptions {
+ bool non_sensitive = 50000;
+ }
We can use this option to mark certain fields as non-sensitive.
- message MyMessage {
- string public_name = 1 [(golang.example.policy.non_sensitive) = true];
- }
+ message MyMessage {
+ string public_name = 1 [(golang.example.policy.non_sensitive) = true];
+ }
Next, we will write a Go function which accepts an arbitrary message
value and removes all the sensitive fields.
- // Redact clears every sensitive field in pb.
- func Redact(pb proto.Message) {
- // ...
- }
+ // Redact clears every sensitive field in pb.
+ func Redact(pb proto.Message) {
+ // ...
+ }
This function accepts a
[[https://pkg.go.dev/google.golang.org/protobuf/proto?tab=doc#Message][`proto.Message`]],
an interface type implemented by all generated message types. This type
is an alias for one defined in the `protoreflect` package:
- type ProtoMessage interface{
- ProtoReflect() Message
- }
+ type ProtoMessage interface{
+ ProtoReflect() Message
+ }
To avoid filling up the namespace of generated
messages, the interface contains only a single method returning a
@@ -112,11 +112,11 @@
[[https://pkg.go.dev/google.golang.org/protobuf/reflect/protoreflect?tab=doc#Message.Range][`protoreflect.Message.Range`]]
method calls a function for every populated field in a message.
- m := pb.ProtoReflect()
- m.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
- // ...
- return true
- })
+ m := pb.ProtoReflect()
+ m.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
+ // ...
+ return true
+ })
The range function is called with a
[[https://pkg.go.dev/google.golang.org/protobuf/reflect/protoreflect?tab=doc#FieldDescriptor][`protoreflect.FieldDescriptor`]]
@@ -129,7 +129,7 @@
method returns the field options as a `google.protobuf.FieldOptions`
message.
- opts := fd.Options().(*descriptorpb.FieldOptions)
+ opts := fd.Options().(*descriptorpb.FieldOptions)
(Why the type assertion? Since the generated `descriptorpb` package
depends on `protoreflect`, the `protoreflect` package can't return the
@@ -137,9 +137,9 @@
We can then check the options to see the value of our extension boolean:
- if proto.GetExtension(opts, policypb.E_NonSensitive).(bool) {
- return true // don't redact non-sensitive fields
- }
+ if proto.GetExtension(opts, policypb.E_NonSensitive).(bool) {
+ return true // don't redact non-sensitive fields
+ }
Note that we are looking at the field _descriptor_ here, not the field
_value_. The information we're interested in lies in the protocol
@@ -155,22 +155,22 @@
Once we have identified a field that needs redaction, clearing it is simple:
- m.Clear(fd)
+ m.Clear(fd)
Putting all the above together, our complete redaction function is:
- // Redact clears every sensitive field in pb.
- func Redact(pb proto.Message) {
- m := pb.ProtoReflect()
- m.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
- opts := fd.Options().(*descriptorpb.FieldOptions)
- if proto.GetExtension(opts, policypb.E_NonSensitive).(bool) {
- return true
- }
- m.Clear(fd)
- return true
- })
- }
+ // Redact clears every sensitive field in pb.
+ func Redact(pb proto.Message) {
+ m := pb.ProtoReflect()
+ m.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
+ opts := fd.Options().(*descriptorpb.FieldOptions)
+ if proto.GetExtension(opts, policypb.E_NonSensitive).(bool) {
+ return true
+ }
+ m.Clear(fd)
+ return true
+ })
+ }
A more complete implementation might recursively descend into
message-valued fields. We hope that this simple example gives a
diff --git a/content/appengine-go111.article b/content/appengine-go111.article
index b2fbb78..3319153 100644
--- a/content/appengine-go111.article
+++ b/content/appengine-go111.article
@@ -55,7 +55,7 @@
With the application code complete, create an `app.yaml` file to specify
the runtime:
- runtime: go111
+ runtime: go111
Finally, set your machine up with a Google Cloud Platform account:
@@ -65,7 +65,7 @@
With all the setup complete, you can deploy using one command:
- gcloud app deploy
+ gcloud app deploy
We think Go developers will find the new Go 1.11 runtime for App Engine an
exciting addition to the available options to run Go applications. There is a
diff --git a/content/contributor-workshop.article b/content/contributor-workshop.article
index 98521ef..3560c6c 100644
--- a/content/contributor-workshop.article
+++ b/content/contributor-workshop.article
@@ -188,12 +188,12 @@
The real fun starts when you clone the Go repo. Ironically, you don't hack on
Go under `$GOPATH`, so I put it in my other workspace (which is `~/Develop`).
- cd $DEV # That's my source code folder outside of $GOPATH
- git clone --depth 1 https://go.googlesource.com/go
+ cd $DEV # That's my source code folder outside of $GOPATH
+ git clone --depth 1 https://go.googlesource.com/go
Then install the handy dandy helper tool, `go-contrib-init`:
- go get -u golang.org/x/tools/cmd/go-contrib-init
+ go get -u golang.org/x/tools/cmd/go-contrib-init
Now you can run `go-contrib-init` from the `go/` folder we cloned above and see
whether or not we're ready to contribute. But hold on if you're following along,
@@ -201,7 +201,7 @@
Next, install `codereview` so you can participate in a Gerrit code review:
- go get -u golang.org/x/review/git-codereview
+ go get -u golang.org/x/review/git-codereview
This package includes `git change` and `git mail` which will replace your
normal workflow of `git commit` and `git push` respectively.
@@ -218,13 +218,13 @@
In the workshop, they sent us into the `scratch` repository, which is a safe place to
fool around in order to master the workflow:
- cd $(go env GOPATH)/src/golang.org/x
- git clone --depth 1 [[https://go.googlesource.com/scratch][go.googlesource.com/scratch]]
+ cd $(go env GOPATH)/src/golang.org/x
+ git clone --depth 1 [[https://go.googlesource.com/scratch][go.googlesource.com/scratch]]
First stop is to `cd` in and run `go-contrib-init` to make sure you're ready to contribute:
- go-contrib-init
- All good. Happy hacking!
+ go-contrib-init
+ All good. Happy hacking!
From there, I made a folder named after my GitHub account, did a `git add -u`
then took `git change` for a spin. It has a hash that keeps track of your work,
@@ -269,14 +269,14 @@
file. They follow the format of test cases followed by "Output" commented out
and then the answers to the tests. For example:
- func ExampleRegexp_FindString() {
- re := regexp.MustCompile("fo.?")
- fmt.Printf("%q\n", re.FindString("seafood"))
- fmt.Printf("%q\n", re.FindString("meat"))
- // Output:
- // "foo"
- // ""
- }
+ func ExampleRegexp_FindString() {
+ re := regexp.MustCompile("fo.?")
+ fmt.Printf("%q\n", re.FindString("seafood"))
+ fmt.Printf("%q\n", re.FindString("meat"))
+ // Output:
+ // "foo"
+ // ""
+ }
Kind of cool, right?? I followed Francesc's lead and added a function
`ExampleQuoteMeta` and added a few I thought would be helpful. From there it's
diff --git a/content/go-cloud.article b/content/go-cloud.article
index 01ef8aa..6dff340 100644
--- a/content/go-cloud.article
+++ b/content/go-cloud.article
@@ -78,44 +78,44 @@
to copy a file from a local disk to a cloud provider.
Let's start by opening an S3 bucket using the included [[https://godoc.org/github.com/google/go-cloud/blob/s3blob][s3blob package]]:
- // setupBucket opens an AWS bucket.
- func setupBucket(ctx context.Context) (*blob.Bucket, error) {
- // Obtain AWS credentials.
- sess, err := session.NewSession(&aws.Config{
- Region: aws.String("us-east-2"),
- })
- if err != nil {
- return nil, err
- }
- // Open a handle to s3://go-cloud-bucket.
- return s3blob.OpenBucket(ctx, sess, "go-cloud-bucket")
- }
+ // setupBucket opens an AWS bucket.
+ func setupBucket(ctx context.Context) (*blob.Bucket, error) {
+ // Obtain AWS credentials.
+ sess, err := session.NewSession(&aws.Config{
+ Region: aws.String("us-east-2"),
+ })
+ if err != nil {
+ return nil, err
+ }
+ // Open a handle to s3://go-cloud-bucket.
+ return s3blob.OpenBucket(ctx, sess, "go-cloud-bucket")
+ }
Once a program has a `*blob.Bucket`, it can create a `*blob.Writer`,
which implements `io.Writer`.
From there, the program can use the `*blob.Writer` to write data to the bucket,
checking that `Close` does not report an error.
- ctx := context.Background()
- b, err := setupBucket(ctx)
- if err != nil {
- log.Fatalf("Failed to open bucket: %v", err)
- }
- data, err := ioutil.ReadFile("gopher.png")
- if err != nil {
- log.Fatalf("Failed to read file: %v", err)
- }
- w, err := b.NewWriter(ctx, "gopher.png", nil)
- if err != nil {
- log.Fatalf("Failed to obtain writer: %v", err)
- }
- _, err = w.Write(data)
- if err != nil {
- log.Fatalf("Failed to write to bucket: %v", err)
- }
- if err := w.Close(); err != nil {
- log.Fatalf("Failed to close: %v", err)
- }
+ ctx := context.Background()
+ b, err := setupBucket(ctx)
+ if err != nil {
+ log.Fatalf("Failed to open bucket: %v", err)
+ }
+ data, err := ioutil.ReadFile("gopher.png")
+ if err != nil {
+ log.Fatalf("Failed to read file: %v", err)
+ }
+ w, err := b.NewWriter(ctx, "gopher.png", nil)
+ if err != nil {
+ log.Fatalf("Failed to obtain writer: %v", err)
+ }
+ _, err = w.Write(data)
+ if err != nil {
+ log.Fatalf("Failed to write to bucket: %v", err)
+ }
+ if err := w.Close(); err != nil {
+ log.Fatalf("Failed to close: %v", err)
+ }
Notice how the logic of using the bucket does not refer to AWS S3.
Go Cloud makes swapping out cloud storage a matter of changing the function
@@ -124,20 +124,20 @@
`*blob.Bucket` using [[https://godoc.org/github.com/google/go-cloud/blob/gcsblob#OpenBucket][`gcsblob.OpenBucket`]]
without changing the code that copies the file:
- // setupBucket opens a GCS bucket.
- func setupBucket(ctx context.Context) (*blob.Bucket, error) {
- // Open GCS bucket.
- creds, err := gcp.DefaultCredentials(ctx)
- if err != nil {
- return nil, err
- }
- c, err := gcp.NewHTTPClient(gcp.DefaultTransport(), gcp.CredentialsTokenSource(creds))
- if err != nil {
- return nil, err
- }
- // Open a handle to gs://go-cloud-bucket.
- return gcsblob.OpenBucket(ctx, "go-cloud-bucket", c)
- }
+ // setupBucket opens a GCS bucket.
+ func setupBucket(ctx context.Context) (*blob.Bucket, error) {
+ // Open GCS bucket.
+ creds, err := gcp.DefaultCredentials(ctx)
+ if err != nil {
+ return nil, err
+ }
+ c, err := gcp.NewHTTPClient(gcp.DefaultTransport(), gcp.CredentialsTokenSource(creds))
+ if err != nil {
+ return nil, err
+ }
+ // Open a handle to gs://go-cloud-bucket.
+ return gcsblob.OpenBucket(ctx, "go-cloud-bucket", c)
+ }
While different steps are needed to access buckets on different cloud providers,
the resulting type used by your application is the same: `*blob.Bucket`.
diff --git a/content/go1.13-errors.article b/content/go1.13-errors.article
index fd3fc4c..8c8c029 100644
--- a/content/go1.13-errors.article
+++ b/content/go1.13-errors.article
@@ -14,12 +14,12 @@
is a type that implements an `Error` method:
- type QueryError struct {
- Query string
- Err error
- }
+ type QueryError struct {
+ Query string
+ Err error
+ }
- func (e *QueryError) Error() string { return e.Query + ": " + e.Err.Error() }
+ func (e *QueryError) Error() string { return e.Query + ": " + e.Err.Error() }
Error types like this one are ubiquitous, and the information they store varies
widely, from timestamps to filenames to server addresses. Often, that
@@ -42,31 +42,31 @@
ways. The most common is to compare an error to `nil` to see if an operation
failed.
- if err != nil {
- // something went wrong
- }
+ if err != nil {
+ // something went wrong
+ }
Sometimes we compare an error to a known _sentinel_ value, to see if a specific error has occurred.
- var ErrNotFound = errors.New("not found")
+ var ErrNotFound = errors.New("not found")
- if err == ErrNotFound {
- // something wasn't found
- }
+ if err == ErrNotFound {
+ // something wasn't found
+ }
An error value may be of any type which satisfies the language-defined `error`
interface. A program can use a type assertion or type switch to view an error
value as a more specific type.
- type NotFoundError struct {
- Name string
- }
+ type NotFoundError struct {
+ Name string
+ }
- func (e *NotFoundError) Error() string { return e.Name + ": not found" }
+ func (e *NotFoundError) Error() string { return e.Name + ": not found" }
- if e, ok := err.(*NotFoundError); ok {
- // e.Name wasn't found
- }
+ if e, ok := err.(*NotFoundError); ok {
+ // e.Name wasn't found
+ }
** Adding information
@@ -76,9 +76,9 @@
simple way to do this is to construct a new error that includes the text of the
previous one:
- if err != nil {
- return fmt.Errorf("decompress %v: %v", name, err)
- }
+ if err != nil {
+ return fmt.Errorf("decompress %v: %v", name, err)
+ }
Creating a new error with `fmt.Errorf` discards everything from the original
error except the text. As we saw above with `QueryError`, we may sometimes want
@@ -86,18 +86,18 @@
inspection by code. Here is `QueryError` again:
- type QueryError struct {
- Query string
- Err error
- }
+ type QueryError struct {
+ Query string
+ Err error
+ }
Programs can look inside a `*QueryError` value to make decisions based on the
underlying error. You'll sometimes see this referred to as "unwrapping" the
error.
- if e, ok := err.(*QueryError); ok && e.Err == ErrPermission {
- // query failed because of a permission problem
- }
+ if e, ok := err.(*QueryError); ok && e.Err == ErrPermission {
+ // query failed because of a permission problem
+ }
The `os.PathError` type in the standard library is another example of one error which contains another.
@@ -116,7 +116,7 @@
Following this convention, we can give the `QueryError` type above an `Unwrap`
method that returns its contained error:
- func (e *QueryError) Unwrap() error { return e.Err }
+ func (e *QueryError) Unwrap() error { return e.Err }
The result of unwrapping an error may itself have an `Unwrap` method; we call
the sequence of errors produced by repeated unwrapping the _error_chain_.
@@ -127,20 +127,20 @@
The `errors.Is` function compares an error to a value.
- // Similar to:
- // if err == ErrNotFound { … }
- if errors.Is(err, ErrNotFound) {
- // something wasn't found
- }
+ // Similar to:
+ // if err == ErrNotFound { … }
+ if errors.Is(err, ErrNotFound) {
+ // something wasn't found
+ }
The `As` function tests whether an error is a specific type.
- // Similar to:
- // if e, ok := err.(*QueryError); ok { … }
- var e *QueryError
- if errors.As(err, &e) {
- // err is a *QueryError, and e is set to the error's value
- }
+ // Similar to:
+ // if e, ok := err.(*QueryError); ok { … }
+ var e *QueryError
+ if errors.As(err, &e) {
+ // err is a *QueryError, and e is set to the error's value
+ }
In the simplest case, the `errors.Is` function behaves like a comparison to a
sentinel error, and the `errors.As` function behaves like a type assertion. When
@@ -148,15 +148,15 @@
a chain. Let's look again at the example from above of unwrapping a `QueryError`
to examine the underlying error:
- if e, ok := err.(*QueryError); ok && e.Err == ErrPermission {
- // query failed because of a permission problem
- }
+ if e, ok := err.(*QueryError); ok && e.Err == ErrPermission {
+ // query failed because of a permission problem
+ }
Using the `errors.Is` function, we can write this as:
- if errors.Is(err, ErrPermission) {
- // err, or some error that it wraps, is a permission problem
- }
+ if errors.Is(err, ErrPermission) {
+ // err, or some error that it wraps, is a permission problem
+ }
The `errors` package also includes a new `Unwrap` function which returns the
@@ -168,25 +168,25 @@
As mentioned earlier, it is common to use the `fmt.Errorf` function to add additional information to an error.
- if err != nil {
- return fmt.Errorf("decompress %v: %v", name, err)
- }
+ if err != nil {
+ return fmt.Errorf("decompress %v: %v", name, err)
+ }
In Go 1.13, the `fmt.Errorf` function supports a new `%w` verb. When this verb
is present, the error returned by `fmt.Errorf` will have an `Unwrap` method
returning the argument of `%w`, which must be an error. In all other ways, `%w`
is identical to `%v`.
- if err != nil {
- // Return an error which unwraps to err.
- return fmt.Errorf("decompress %v: %w", name, err)
- }
+ if err != nil {
+ // Return an error which unwraps to err.
+ return fmt.Errorf("decompress %v: %w", name, err)
+ }
Wrapping an error with `%w` makes it available to `errors.Is` and `errors.As`:
- err := fmt.Errorf("access denied: %w", ErrPermission)
- ...
- if errors.Is(err, ErrPermission) ...
+ err := fmt.Errorf("access denied: %w", ErrPermission)
+ ...
+ if errors.Is(err, ErrPermission) ...
** Whether to Wrap
@@ -215,8 +215,8 @@
the function instead returns `fmt.Errorf("accessing`DB:`%w",`err)`, then a
caller could reasonably write
- err := pkg.LookupUser(...)
- if errors.Is(err, sql.ErrNoRows) …
+ err := pkg.LookupUser(...)
+ if errors.Is(err, sql.ErrNoRows) …
At that point, the function must always return `sql.ErrNoRows` if you don't want
to break your clients, even if you switch to a different database package. In
@@ -242,23 +242,23 @@
which compares an error against a template, considering only fields which are
non-zero in the template:
- type Error struct {
- Path string
- User string
- }
+ type Error struct {
+ Path string
+ User string
+ }
- func (e *Error) Is(target error) bool {
- t, ok := target.(*Error)
- if !ok {
- return false
- }
- return (e.Path == t.Path || t.Path == "") &&
- (e.User == t.User || t.User == "")
- }
+ func (e *Error) Is(target error) bool {
+ t, ok := target.(*Error)
+ if !ok {
+ return false
+ }
+ return (e.Path == t.Path || t.Path == "") &&
+ (e.User == t.User || t.User == "")
+ }
- if errors.Is(err, &Error{User: "someuser"}) {
- // err's User field is "someuser".
- }
+ if errors.Is(err, &Error{User: "someuser"}) {
+ // err's User field is "someuser".
+ }
The `errors.As` function similarly consults an `As` method when present.
@@ -275,18 +275,18 @@
If we wish a function to return an identifiable error condition, such as "item
not found," we might return an error wrapping a sentinel.
- var ErrNotFound = errors.New("not found")
+ var ErrNotFound = errors.New("not found")
- // FetchItem returns the named item.
- //
- // If no item with the name exists, FetchItem returns an error
- // wrapping ErrNotFound.
- func FetchItem(name string) (*Item, error) {
- if itemNotFound(name) {
- return nil, fmt.Errorf("%q: %w", name, ErrNotFound)
- }
- // ...
- }
+ // FetchItem returns the named item.
+ //
+ // If no item with the name exists, FetchItem returns an error
+ // wrapping ErrNotFound.
+ func FetchItem(name string) (*Item, error) {
+ if itemNotFound(name) {
+ return nil, fmt.Errorf("%q: %w", name, ErrNotFound)
+ }
+ // ...
+ }
There are other existing patterns for providing errors which can be semantically
examined by the caller, such as directly returning a sentinel value, a specific
@@ -298,39 +298,39 @@
not expose the underlying error, unless you are willing to commit to returning
that specific error in the future.
- f, err := os.Open(filename)
- if err != nil {
- // The *os.PathError returned by os.Open is an internal detail.
- // To avoid exposing it to the caller, repackage it as a new
- // error with the same text. We use the %v formatting verb, since
- // %w would permit the caller to unwrap the original *os.PathError.
- return fmt.Errorf("%v", err)
- }
+ f, err := os.Open(filename)
+ if err != nil {
+ // The *os.PathError returned by os.Open is an internal detail.
+ // To avoid exposing it to the caller, repackage it as a new
+ // error with the same text. We use the %v formatting verb, since
+ // %w would permit the caller to unwrap the original *os.PathError.
+ return fmt.Errorf("%v", err)
+ }
If a function is defined as returning an error wrapping some sentinel or type,
do not return the underlying error directly.
- var ErrPermission = errors.New("permission denied")
+ var ErrPermission = errors.New("permission denied")
- // DoSomething returns an error wrapping ErrPermission if the user
- // does not have permission to do something.
- func DoSomething() error {
- if !userHasPermission() {
- // If we return ErrPermission directly, callers might come
- // to depend on the exact error value, writing code like this:
- //
- // if err := pkg.DoSomething(); err == pkg.ErrPermission { … }
- //
- // This will cause problems if we want to add additional
- // context to the error in the future. To avoid this, we
- // return an error wrapping the sentinel so that users must
- // always unwrap it:
- //
- // if err := pkg.DoSomething(); errors.Is(err, pkg.ErrPermission) { ... }
- return fmt.Errorf("%w", ErrPermission)
- }
- // ...
- }
+ // DoSomething returns an error wrapping ErrPermission if the user
+ // does not have permission to do something.
+ func DoSomething() error {
+ if !userHasPermission() {
+ // If we return ErrPermission directly, callers might come
+ // to depend on the exact error value, writing code like this:
+ //
+ // if err := pkg.DoSomething(); err == pkg.ErrPermission { … }
+ //
+ // This will cause problems if we want to add additional
+ // context to the error in the future. To avoid this, we
+ // return an error wrapping the sentinel so that users must
+ // always unwrap it:
+ //
+ // if err := pkg.DoSomething(); errors.Is(err, pkg.ErrPermission) { ... }
+ return fmt.Errorf("%w", ErrPermission)
+ }
+ // ...
+ }
* Conclusion
diff --git a/content/h2push.article b/content/h2push.article
index 9079f8d..519eb92 100644
--- a/content/h2push.article
+++ b/content/h2push.article
@@ -58,7 +58,7 @@
A fully working example is available at:
- $ go get golang.org/x/blog/content/h2push/server
+ $ go get golang.org/x/blog/content/h2push/server
If you run the server and load [[https://localhost:8080][https://localhost:8080]],
@@ -75,9 +75,9 @@
response:
- <html>
- <head>
- <link rel="stylesheet" href="a.css">...
+ <html>
+ <head>
+ <link rel="stylesheet" href="a.css">...
Then you call Push("a.css", nil). The browser may parse this fragment
diff --git a/content/http-tracing.article b/content/http-tracing.article
index ae14d57..710ae60 100644
--- a/content/http-tracing.article
+++ b/content/http-tracing.article
@@ -57,8 +57,8 @@
The program will follow the redirect of google.com to www.google.com and will output:
- Connection reused for https://google.com? false
- Connection reused for https://www.google.com/? false
+ Connection reused for https://google.com? false
+ Connection reused for https://www.google.com/? false
The Transport in the `net/http` package supports tracing of both HTTP/1
and HTTP/2 requests.
diff --git a/content/migrating-to-go-modules.article b/content/migrating-to-go-modules.article
index 3e5fbc5..e3c8759 100644
--- a/content/migrating-to-go-modules.article
+++ b/content/migrating-to-go-modules.article
@@ -45,37 +45,37 @@
To convert a project that already uses a dependency management tool, run the following commands:
- $ git clone https://github.com/my/project
- [...]
- $ cd project
- $ cat Godeps/Godeps.json
- {
- "ImportPath": "github.com/my/project",
- "GoVersion": "go1.12",
- "GodepVersion": "v80",
- "Deps": [
- {
- "ImportPath": "rsc.io/binaryregexp",
- "Comment": "v0.2.0-1-g545cabd",
- "Rev": "545cabda89ca36b48b8e681a30d9d769a30b3074"
- },
- {
- "ImportPath": "rsc.io/binaryregexp/syntax",
- "Comment": "v0.2.0-1-g545cabd",
- "Rev": "545cabda89ca36b48b8e681a30d9d769a30b3074"
- }
- ]
- }
- $ go mod init github.com/my/project
- go: creating new go.mod: module github.com/my/project
- go: copying requirements from Godeps/Godeps.json
- $ cat go.mod
- module github.com/my/project
+ $ git clone https://github.com/my/project
+ [...]
+ $ cd project
+ $ cat Godeps/Godeps.json
+ {
+ "ImportPath": "github.com/my/project",
+ "GoVersion": "go1.12",
+ "GodepVersion": "v80",
+ "Deps": [
+ {
+ "ImportPath": "rsc.io/binaryregexp",
+ "Comment": "v0.2.0-1-g545cabd",
+ "Rev": "545cabda89ca36b48b8e681a30d9d769a30b3074"
+ },
+ {
+ "ImportPath": "rsc.io/binaryregexp/syntax",
+ "Comment": "v0.2.0-1-g545cabd",
+ "Rev": "545cabda89ca36b48b8e681a30d9d769a30b3074"
+ }
+ ]
+ }
+ $ go mod init github.com/my/project
+ go: creating new go.mod: module github.com/my/project
+ go: copying requirements from Godeps/Godeps.json
+ $ cat go.mod
+ module github.com/my/project
- go 1.12
+ go 1.12
- require rsc.io/binaryregexp v0.2.1-0.20190524193500-545cabda89ca
- $
+ require rsc.io/binaryregexp v0.2.1-0.20190524193500-545cabda89ca
+ $
`go`mod`init` creates a new go.mod file and automatically imports dependencies from `Godeps.json`,
`Gopkg.lock`, or a number of [[https://go.googlesource.com/go/+/362625209b6cd2bc059b6b0a67712ddebab312d9/src/cmd/go/internal/modconv/modconv.go#9][other supported formats]].
@@ -87,13 +87,13 @@
so if you prefer to take an iterative approach,
this is the closest your `go.mod` file will be to your pre-modules dependency specification.
- $ go mod tidy
- go: downloading rsc.io/binaryregexp v0.2.1-0.20190524193500-545cabda89ca
- go: extracting rsc.io/binaryregexp v0.2.1-0.20190524193500-545cabda89ca
- $ cat go.sum
- rsc.io/binaryregexp v0.2.1-0.20190524193500-545cabda89ca h1:FKXXXJ6G2bFoVe7hX3kEX6Izxw5ZKRH57DFBJmHCbkU=
- rsc.io/binaryregexp v0.2.1-0.20190524193500-545cabda89ca/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
- $
+ $ go mod tidy
+ go: downloading rsc.io/binaryregexp v0.2.1-0.20190524193500-545cabda89ca
+ go: extracting rsc.io/binaryregexp v0.2.1-0.20190524193500-545cabda89ca
+ $ cat go.sum
+ rsc.io/binaryregexp v0.2.1-0.20190524193500-545cabda89ca h1:FKXXXJ6G2bFoVe7hX3kEX6Izxw5ZKRH57DFBJmHCbkU=
+ rsc.io/binaryregexp v0.2.1-0.20190524193500-545cabda89ca/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
+ $
`go`mod`tidy` finds all the packages transitively imported by packages in your module.
It adds new module requirements for packages not provided by any known module,
@@ -106,10 +106,10 @@
Let's finish by making sure the code builds and tests pass:
- $ go build ./...
- $ go test ./...
- [...]
- $
+ $ go build ./...
+ $ go test ./...
+ [...]
+ $
Note that other dependency managers may specify dependencies at the level
of individual packages or entire repositories (not modules),
@@ -120,11 +120,11 @@
Therefore, it's important to follow the above commands with an audit of
the resulting dependencies. To do so, run
- $ go list -m all
- go: finding rsc.io/binaryregexp v0.2.1-0.20190524193500-545cabda89ca
- github.com/my/project
- rsc.io/binaryregexp v0.2.1-0.20190524193500-545cabda89ca
- $
+ $ go list -m all
+ go: finding rsc.io/binaryregexp v0.2.1-0.20190524193500-545cabda89ca
+ github.com/my/project
+ rsc.io/binaryregexp v0.2.1-0.20190524193500-545cabda89ca
+ $
and compare the resulting versions with your old dependency management file
to ensure that the selected versions are appropriate.
@@ -134,27 +134,27 @@
(If the version you request is older than the version that was previously selected,
`go`get` will downgrade other dependencies as needed to maintain compatibility.) For example,
- $ go mod why -m rsc.io/binaryregexp
- [...]
- $ go mod graph | grep rsc.io/binaryregexp
- [...]
- $ go get rsc.io/binaryregexp@v0.2.0
- $
+ $ go mod why -m rsc.io/binaryregexp
+ [...]
+ $ go mod graph | grep rsc.io/binaryregexp
+ [...]
+ $ go get rsc.io/binaryregexp@v0.2.0
+ $
* Without a dependency manager
For a Go project without a dependency management system, start by creating a `go.mod` file:
- $ git clone https://go.googlesource.com/blog
- [...]
- $ cd blog
- $ go mod init golang.org/x/blog
- go: creating new go.mod: module golang.org/x/blog
- $ cat go.mod
- module golang.org/x/blog
+ $ git clone https://go.googlesource.com/blog
+ [...]
+ $ cd blog
+ $ go mod init golang.org/x/blog
+ go: creating new go.mod: module golang.org/x/blog
+ $ cat go.mod
+ module golang.org/x/blog
- go 1.12
- $
+ go 1.12
+ $
Without a configuration file from a previous dependency manager,
`go`mod`init` will create a `go.mod` file with only the `module` and `go` directives.
@@ -169,58 +169,58 @@
Next, run `go`mod`tidy` to add the module's dependencies:
- $ go mod tidy
- go: finding golang.org/x/website latest
- go: finding gopkg.in/tomb.v2 latest
- go: finding golang.org/x/net latest
- go: finding golang.org/x/tools latest
- go: downloading github.com/gorilla/context v1.1.1
- go: downloading golang.org/x/tools v0.0.0-20190813214729-9dba7caff850
- go: downloading golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7
- go: extracting github.com/gorilla/context v1.1.1
- go: extracting golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7
- go: downloading gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637
- go: extracting gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637
- go: extracting golang.org/x/tools v0.0.0-20190813214729-9dba7caff850
- go: downloading golang.org/x/website v0.0.0-20190809153340-86a7442ada7c
- go: extracting golang.org/x/website v0.0.0-20190809153340-86a7442ada7c
- $ cat go.mod
- module golang.org/x/blog
+ $ go mod tidy
+ go: finding golang.org/x/website latest
+ go: finding gopkg.in/tomb.v2 latest
+ go: finding golang.org/x/net latest
+ go: finding golang.org/x/tools latest
+ go: downloading github.com/gorilla/context v1.1.1
+ go: downloading golang.org/x/tools v0.0.0-20190813214729-9dba7caff850
+ go: downloading golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7
+ go: extracting github.com/gorilla/context v1.1.1
+ go: extracting golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7
+ go: downloading gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637
+ go: extracting gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637
+ go: extracting golang.org/x/tools v0.0.0-20190813214729-9dba7caff850
+ go: downloading golang.org/x/website v0.0.0-20190809153340-86a7442ada7c
+ go: extracting golang.org/x/website v0.0.0-20190809153340-86a7442ada7c
+ $ cat go.mod
+ module golang.org/x/blog
- go 1.12
+ go 1.12
- require (
- github.com/gorilla/context v1.1.1
- golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7
- golang.org/x/text v0.3.2
- golang.org/x/tools v0.0.0-20190813214729-9dba7caff850
- golang.org/x/website v0.0.0-20190809153340-86a7442ada7c
- gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637
- )
- $ cat go.sum
- cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
- cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
- git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
- git.apache.org/thrift.git v0.0.0-20181218151757-9b75e4fe745a/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
- github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
- [...]
- $
+ require (
+ github.com/gorilla/context v1.1.1
+ golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7
+ golang.org/x/text v0.3.2
+ golang.org/x/tools v0.0.0-20190813214729-9dba7caff850
+ golang.org/x/website v0.0.0-20190809153340-86a7442ada7c
+ gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637
+ )
+ $ cat go.sum
+ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+ cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+ git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
+ git.apache.org/thrift.git v0.0.0-20181218151757-9b75e4fe745a/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
+ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
+ [...]
+ $
`go`mod`tidy` added module requirements for all the packages transitively
imported by packages in your module and built a `go.sum` with checksums
for each library at a specific version.
Let's finish by making sure the code still builds and tests still pass:
- $ go build ./...
- $ go test ./...
- ok golang.org/x/blog 0.335s
- ? golang.org/x/blog/content/appengine [no test files]
- ok golang.org/x/blog/content/cover 0.040s
- ? golang.org/x/blog/content/h2push/server [no test files]
- ? golang.org/x/blog/content/survey2016 [no test files]
- ? golang.org/x/blog/content/survey2017 [no test files]
- ? golang.org/x/blog/support/racy [no test files]
- $
+ $ go build ./...
+ $ go test ./...
+ ok golang.org/x/blog 0.335s
+ ? golang.org/x/blog/content/appengine [no test files]
+ ok golang.org/x/blog/content/cover 0.040s
+ ? golang.org/x/blog/content/h2push/server [no test files]
+ ? golang.org/x/blog/content/survey2016 [no test files]
+ ? golang.org/x/blog/content/survey2017 [no test files]
+ ? golang.org/x/blog/support/racy [no test files]
+ $
Note that when `go`mod`tidy` adds a requirement,
it adds the latest version of the module.
@@ -260,8 +260,8 @@
commits using [[https://golang.org/cmd/go/#hdr-Pseudo_versions][pseudo-versions]],
which may be more difficult to support.
- $ git tag v1.2.0
- $ git push origin v1.2.0
+ $ git tag v1.2.0
+ $ git push origin v1.2.0
Your new `go.mod` file defines a canonical import path for your module and adds
new minimum version requirements. If your users are already using the correct
diff --git a/content/module-mirror-launch.article b/content/module-mirror-launch.article
index 2bef6e4..d86a716 100644
--- a/content/module-mirror-launch.article
+++ b/content/module-mirror-launch.article
@@ -116,8 +116,8 @@
against the checksum database with
[[https://godoc.org/golang.org/x/mod/gosumcheck][gosumcheck]]:
- $ go get golang.org/x/mod/gosumcheck
- $ gosumcheck /path/to/go.sum
+ $ go get golang.org/x/mod/gosumcheck
+ $ gosumcheck /path/to/go.sum
In addition to verification done by the `go` command, third-party
auditors can hold the checksum database accountable by iterating over the log
diff --git a/content/package-names.article b/content/package-names.article
index 967f02c..2cd74d1 100644
--- a/content/package-names.article
+++ b/content/package-names.article
@@ -86,13 +86,13 @@
start := time.Now() // start is a time.Time
t, err := time.Parse(time.Kitchen, "6:06PM") // t is a time.Time
- ctx = context.WithTimeout(ctx, 10*time.Millisecond) // ctx is a context.Context
- ip, ok := userip.FromContext(ctx) // ip is a net.IP
+ ctx = context.WithTimeout(ctx, 10*time.Millisecond) // ctx is a context.Context
+ ip, ok := userip.FromContext(ctx) // ip is a net.IP
A function named `New` in package `pkg` returns a value of type `pkg.Pkg`.
This is a standard entry point for client code using that type:
- q := list.New() // q is a *list.List
+ q := list.New() // q is a *list.List
When a function returns a value of type `pkg.T`, where `T` is not `Pkg`, the
function name may include `T` to make client code easier to understand.
diff --git a/content/pipelines.article b/content/pipelines.article
index de145a1..194b26c 100644
--- a/content/pipelines.article
+++ b/content/pipelines.article
@@ -122,10 +122,10 @@
number of values; send operations complete immediately if there's room in the
buffer:
- c := make(chan int, 2) // buffer size 2
- c <- 1 // succeeds immediately
- c <- 2 // succeeds immediately
- c <- 3 // blocks until another goroutine does <-c and receives 1
+ c := make(chan int, 2) // buffer size 2
+ c <- 1 // succeeds immediately
+ c <- 2 // succeeds immediately
+ c <- 3 // blocks until another goroutine does <-c and receives 1
When the number of values to be sent is known at channel creation time, a buffer
can simplify the code. For example, we can rewrite `gen` to copy the list of
diff --git a/content/v2-go-modules.article b/content/v2-go-modules.article
index db2c0cd..54b7e5a 100644
--- a/content/v2-go-modules.article
+++ b/content/v2-go-modules.article
@@ -34,8 +34,8 @@
Modules formalized an important principle in Go, the
[[https://research.swtch.com/vgo-import][*import*compatibility*rule*]]:
- If an old package and a new package have the same import path,
- the new package must be backwards compatible with the old package.
+ If an old package and a new package have the same import path,
+ the new package must be backwards compatible with the old package.
By definition, a new major version of a package is not backwards compatible with
the previous version. This means a new major version of a module must have a
@@ -64,9 +64,9 @@
The recommended strategy is to develop `v2+` modules in a directory named after
the major version suffix.
- github.com/googleapis/gax-go @ master branch
- /go.mod → module github.com/googleapis/gax-go
- /v2/go.mod → module github.com/googleapis/gax-go/v2
+ github.com/googleapis/gax-go @ master branch
+ /go.mod → module github.com/googleapis/gax-go
+ /v2/go.mod → module github.com/googleapis/gax-go/v2
This approach is compatible with tools that aren't aware of modules: file paths
within the repository match the paths expected by `go`get` in `GOPATH` mode.
@@ -86,51 +86,51 @@
This post uses `github.com/googleapis/gax-go` as an example:
- $ pwd
- /tmp/gax-go
- $ ls
- CODE_OF_CONDUCT.md call_option.go internal
- CONTRIBUTING.md gax.go invoke.go
- LICENSE go.mod tools.go
- README.md go.sum RELEASING.md
- header.go
- $ cat go.mod
- module github.com/googleapis/gax-go
-
- go 1.9
-
- require (
- github.com/golang/protobuf v1.3.1
- golang.org/x/exp v0.0.0-20190221220918-438050ddec5e
- golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3
- golang.org/x/tools v0.0.0-20190114222345-bf090417da8b
- google.golang.org/grpc v1.19.0
- honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099
- )
- $
+ $ pwd
+ /tmp/gax-go
+ $ ls
+ CODE_OF_CONDUCT.md call_option.go internal
+ CONTRIBUTING.md gax.go invoke.go
+ LICENSE go.mod tools.go
+ README.md go.sum RELEASING.md
+ header.go
+ $ cat go.mod
+ module github.com/googleapis/gax-go
+
+ go 1.9
+
+ require (
+ github.com/golang/protobuf v1.3.1
+ golang.org/x/exp v0.0.0-20190221220918-438050ddec5e
+ golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3
+ golang.org/x/tools v0.0.0-20190114222345-bf090417da8b
+ google.golang.org/grpc v1.19.0
+ honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099
+ )
+ $
To start development on `v2` of `github.com/googleapis/gax-go`, we'll create a
new `v2/` directory and copy our package into it.
- $ mkdir v2
- $ cp *.go v2/
- building file list ... done
- call_option.go
- gax.go
- header.go
- invoke.go
- tools.go
-
- sent 10588 bytes received 130 bytes 21436.00 bytes/sec
- total size is 10208 speedup is 0.95
- $
+ $ mkdir v2
+ $ cp *.go v2/
+ building file list ... done
+ call_option.go
+ gax.go
+ header.go
+ invoke.go
+ tools.go
+
+ sent 10588 bytes received 130 bytes 21436.00 bytes/sec
+ total size is 10208 speedup is 0.95
+ $
Now, let's create a v2 `go.mod` file by copying the current `go.mod` file and
adding a `v2/` suffix to the module path:
- $ cp go.mod v2/go.mod
- $ go mod edit -module github.com/googleapis/gax-go/v2 v2/go.mod
- $
+ $ cp go.mod v2/go.mod
+ $ go mod edit -module github.com/googleapis/gax-go/v2 v2/go.mod
+ $
Note that the `v2` version is treated as a separate module from the `v0`/`v1`
versions: both may coexist in the same build. So, if your `v2+` module has
@@ -139,10 +139,10 @@
to update all `github.com/my/project` references to `github.com/my/project/v2`,
you can use `find` and `sed`:
- $ find . -type f \
- -name '*.go' \
- -exec sed -i -e 's,github.com/my/project,github.com/my/project/v2,g' {} \;
- $
+ $ find . -type f \
+ -name '*.go' \
+ -exec sed -i -e 's,github.com/my/project,github.com/my/project/v2,g' {} \;
+ $
Now we have a `v2` module, but we want to experiment and make changes before
publishing a release. Until we release `v2.0.0` (or any version without a
@@ -150,16 +150,16 @@
the new API. If we want users to be able to experiment with the new API before
we officially make it stable, we can publish a `v2` pre-release version:
- $ git tag v2.0.0-alpha.1
- $ git push origin v2.0.0-alpha.1
- $
+ $ git tag v2.0.0-alpha.1
+ $ git push origin v2.0.0-alpha.1
+ $
Once we are happy with our `v2` API and are sure we don't need any other breaking
changes, we can tag `v2.0.0`:
- $ git tag v2.0.0
- $ git push origin v2.0.0
- $
+ $ git tag v2.0.0
+ $ git push origin v2.0.0
+ $
At that point, there are now two major versions to maintain. Backwards
compatible changes and bug fixes will lead to new minor and patch releases
diff --git a/content/wire.article b/content/wire.article
index 40b8f33..2d9ca5b 100644
--- a/content/wire.article
+++ b/content/wire.article
@@ -18,8 +18,8 @@
by explicitly providing components with all of the dependencies they need to work.
In Go, this often takes the form of passing dependencies to constructors:
- // NewUserStore returns a UserStore that uses cfg and db as dependencies.
- func NewUserStore(cfg *Config, db *mysql.DB) (*UserStore, error) {...}
+ // NewUserStore returns a UserStore that uses cfg and db as dependencies.
+ func NewUserStore(cfg *Config, db *mysql.DB) (*UserStore, error) {...}
This technique works great at small scale,
but larger applications can have a complex graph of dependencies,
@@ -101,69 +101,69 @@
which are described simply as parameters to the function.
Here's some sample code that defines three providers:
- // NewUserStore is the same function we saw above; it is a provider for UserStore,
- // with dependencies on *Config and *mysql.DB.
- func NewUserStore(cfg *Config, db *mysql.DB) (*UserStore, error) {...}
+ // NewUserStore is the same function we saw above; it is a provider for UserStore,
+ // with dependencies on *Config and *mysql.DB.
+ func NewUserStore(cfg *Config, db *mysql.DB) (*UserStore, error) {...}
- // NewDefaultConfig is a provider for *Config, with no dependencies.
- func NewDefaultConfig() *Config {...}
+ // NewDefaultConfig is a provider for *Config, with no dependencies.
+ func NewDefaultConfig() *Config {...}
- // NewDB is a provider for *mysql.DB based on some connection info.
- func NewDB(info *ConnectionInfo) (*mysql.DB, error) {...}
+ // NewDB is a provider for *mysql.DB based on some connection info.
+ func NewDB(info *ConnectionInfo) (*mysql.DB, error) {...}
Providers that are commonly used together can be grouped into `ProviderSets`.
For example, it's common to use a default `*Config` when creating a `*UserStore`,
so we can group `NewUserStore` and `NewDefaultConfig` in a `ProviderSet`:
- var UserStoreSet = wire.ProviderSet(NewUserStore, NewDefaultConfig)
+ var UserStoreSet = wire.ProviderSet(NewUserStore, NewDefaultConfig)
_Injectors_ are generated functions that call providers in dependency order.
You write the injector's signature, including any needed inputs as arguments,
and insert a call to `wire.Build` with the list of providers or provider
sets that are needed to construct the end result:
- func initUserStore() (*UserStore, error) {
- // We're going to get an error, because NewDB requires a *ConnectionInfo
- // and we didn't provide one.
- wire.Build(UserStoreSet, NewDB)
- return nil, nil // These return values are ignored.
- }
+ func initUserStore() (*UserStore, error) {
+ // We're going to get an error, because NewDB requires a *ConnectionInfo
+ // and we didn't provide one.
+ wire.Build(UserStoreSet, NewDB)
+ return nil, nil // These return values are ignored.
+ }
Now we run go generate to execute wire:
- $ go generate
- wire.go:2:10: inject initUserStore: no provider found for ConnectionInfo (required by provider of *mysql.DB)
- wire: generate failed
+ $ go generate
+ wire.go:2:10: inject initUserStore: no provider found for ConnectionInfo (required by provider of *mysql.DB)
+ wire: generate failed
Oops! We didn't include a `ConnectionInfo` or tell Wire how to build one.
Wire helpfully tells us the line number and types involved.
We can either add a provider for it to `wire.Build`,
or add it as an argument:
- func initUserStore(info ConnectionInfo) (*UserStore, error) {
- wire.Build(UserStoreSet, NewDB)
- return nil, nil // These return values are ignored.
- }
+ func initUserStore(info ConnectionInfo) (*UserStore, error) {
+ wire.Build(UserStoreSet, NewDB)
+ return nil, nil // These return values are ignored.
+ }
Now `go generate` will create a new file with the generated code:
- // File: wire_gen.go
- // Code generated by Wire. DO NOT EDIT.
- //go:generate wire
- //+build !wireinject
+ // File: wire_gen.go
+ // Code generated by Wire. DO NOT EDIT.
+ //go:generate wire
+ //+build !wireinject
- func initUserStore(info ConnectionInfo) (*UserStore, error) {
- defaultConfig := NewDefaultConfig()
- db, err := NewDB(info)
- if err != nil {
- return nil, err
- }
- userStore, err := NewUserStore(defaultConfig, db)
- if err != nil {
- return nil, err
- }
- return userStore, nil
- }
+ func initUserStore(info ConnectionInfo) (*UserStore, error) {
+ defaultConfig := NewDefaultConfig()
+ db, err := NewDB(info)
+ if err != nil {
+ return nil, err
+ }
+ userStore, err := NewUserStore(defaultConfig, db)
+ if err != nil {
+ return nil, err
+ }
+ return userStore, nil
+ }
Any non-injector declarations are copied into the generated file.
There is no dependency on Wire at runtime: