You have 2 free member-only stories left this month.

Easy to trip when learning Go FAQ

Ask people inside and outside the company about what is difficult to understand when writing Go for the first time, and what are the difficult points for people who are familiar with other languages. I tried to summarize it. There are many more, but there are too many, so first of all, this is the place. It is expected that more and more people will develop with containers, and at that time, more and more people will start using Go, which has excellent compatibility with containers.

Go is a concept that makes the core of the language simple, and when you realize something, combine the simple functions. In other words, Go covers a wider area of ​​combinations (idioms) than what you want to achieve or can do in other languages. Providing information that will give you a clue about that will reduce stumbling blocks for those who will touch Go in the future.

Difference in appearance

People who are familiar with Go and those who are not familiar with it will see a very different view when looking at the same code, and the way they use their heads when writing code will also be quite different.

Play vs Recognize

Cognitive psychology considers two modes of memory: regeneration and recognition.

Playback is a state in which you can remember past memories without any input. Reconfirmation is a state where you can remember “Oh, this has been experienced” when asked “Have you experienced this?”

In order to play it, you have to remember it completely. People who are used to it remember a lot of patterns and can write code by playing them, and when they see other people’s code, they can compare it with past patterns and “better code”. I come up with patterns.

Reconfirmation is less difficult. We will implement it by combining it while tracing the documents, sample code, information searched on the net, and so on. It takes time, and performance will drop if the pattern does not appear in the search. However, if you look at the code over and over and re-acknowledge it repeatedly, you will be able to write the code by playing it. The goal of this document is to improve the efficiency of recognition.

However, not everyone needs to be at playback level. Even if you’re used to Go, if you use a package you don’t normally use (such as encryption of a crypto package), you’ll have to re-acknowledge (copy and paste the sample) and write the code. Even if you are an advanced user, by creating your own snippet collection, you can save your memory ability and not reduce your performance.

Unlearning

Knowledge that you have already learned tends to hinder your learning. It is quite difficult to eliminate this bias (objectify) and learn again. Isn’t it necessary to have some kind of plus-alpha ability, such as sci-fi lovers who reset (recombined) their knowledge and enjoy it, or lovers of Ace Attorney?

Expressing the difference in the received words and teaching it is a quick way to eliminate this start stumbling block. And once you move your hands, new ideas will take root. Until then, you will need to watch with warm eyes.

Being able to unlearn well means that the knowledge you have up to that point will be objectiveized, so it is possible that the language you have learned in the past will improve on your own.

Collection of mounting patterns

Let’s explain. It may be divided into categories. Unify in the following format.

  • What is Go’s way of using this? (What is the one that people who are used to often choose)
  • I want to do something like I did in this language, but what should I do?
  • If you can’t, why
  • If there are multiple, trade off with each option
  • Go has this feature, how do you use it?

package

Q: Where should the repository be in the first place?

Is it possible to make a suitable folder a working folder?

A: Go is $GOPATHplaced in various environment variables. The default is $HOME/go. This is not just the source code, but the pre-built libraries and so on. If you create a working folder for the time being, $GOPATHlet's set it as direnv so that it will be there .

If you want to completely separate each project, $GOPATHcut the top folder as much as you need and use it. If it's not so strict, $HOME/goI think the default is fine.

$GOPATHThe following is as follows. If the app is the application you want to create, create a folder there and git init. Even if you do go get, it will be downloaded here.

$ GOPATH 
+ bin
| ... Executable file obtained and built with go get
+ pkg
| + [os_arch]
| | + ... Pre-built library
| + mod
| | + ... Package downloaded with go mod Cache
| + dep
| + ... Now the cache of packages downloaded with the old dep command
+ src
+ github.com
+ user
+ app
+ library

When creating a separate project in multiple repositories, put it in the same place. However, the dependent library side tries to use the version downloaded from github etc. and put under pkg / mod. It would be inconvenient to have to git push an unstable version if you want to develop it together. Fortunately, go.mod has a feature called replace. If the app uses the library, add the following line to the app’s go.mod and it will reference the folder in the same location. This method is the best way to verify the operation while changing multiple repositories together.

replace ( 
github.com/user/library => ../ library
)

memo: In Go 1.12, $GOPATHgo.mod is not automatically enabled in the following GO111MODULE=on, so let's put in in the environment variable setting . It will be unnecessary in a few months.

It is not too elaborate to build an environment, and a large number of defaults is less likely to deviate from the information in the world, and it is easier to look back at it later. Overly elaborate Makefiles and shell scripts can be expensive to take over, and it’s easy to forget them yourself.

Q: How should functions and structures be placed in packages (directories) and files?

Each language handles packages, modules, and files quite differently. How do I store functions in Go? For example, in Java, folders are packages. The file is associated with the class. JavaScript and Python are modules for each file, and the directory automatically reads the default file ( index.jsor __init__.py).

A: In Go, directories are packages. All files in the directory must have the same package name. On the other hand, moving elements between files does not make a difference at build time.

Write functions, structures, variables, etc. in files inside the directory. There is no rule to write something in one file. It can be said that this area is close to Python and JavaScript.

If a.go and b.go are in the same directory, the elements defined in a.go can be used without declaring anything from b.go. As for the scope, it’s more like Java. In that respect, no matter where you put the files, moving between the files makes no difference at build time. At first, you can put everything in one file, and when it gets bigger, you can divide it into files in units such as code grouping in the package.

The only conditional compilation, when implementing conditional compilation such as a function that is used only for Windows and only for Linux, is included or excluded in the build for each file, so divide it by that unit.

Q: What is the standard folder structure when creating a project?

What kind of project structure should I use when creating a new project?

A: It depends on whether it is a library, a library + CLI tool, or a web server.

This is not mentioned in Go references, but it is a folder structure that is commonly used.

For libraries, the top folder is the root of the library. Go mod init at the root of the repository. The beginning of code.go is pakckage yourlib, and the one for go.mod is module github.com/yourname/yourlib. In the README go get -u github.com/yourname/yourlib, install it with and write it.

+     github.com 
+ yourname
+ yourlib ← This is the root of the repository
+ code.go
+ go.mod
+ go.sum
+ README

If the library provides CLI tools as a bonus, create a cmd folder, create a folder with the command name in it, and put the source of the executable file in it. In the case of Go, the name of the folder where the build was executed is the name of the executable file by default. You can now name artifacts in go modules, but it’s a common practice before that.

To provide multiple commands, create multiple folders under cmd. Each executable is natural package main. In the README go get -u github.com/yourname/yourlib/..., install it with and write it.

+     github.com 
+ yourname
+ yourlib ← This is the root of the repository
+ cmd
| + yourcmd
| + main.go
+ code.go
+ go.mod
+ go.sum

For web service projects, the top folder is the root of the application. Go mod init at the root of the repository. Since it is an executable file, the beginning of main.go pakckage mainwill be, and go.mod module github.com/yourname/yourappwill be. Alternatively, go mod init yourappyou can run: In that case, module yourappit becomes. In the README go get -u github.com/yourname/yourapp, install it with and write it.

For web service projects, the top folder is the root of the application. Go mod init at the root of the repository. Since it is an executable file, the beginning of main.go pakckage mainwill be, and go.mod module github.com/yourname/yourappwill be. Alternatively, go mod init yourappyou can run: In that case, module yourappit becomes. In the README go get -u github.com/yourname/yourapp, install it with and write it.

+     github.com 
+ yourname
+ yourapp ← This is the root of the repository
+ main.go
+ go.mod
+ go.sum
+ README

Q: What should I use to name a package or folder?

You can name the packages and folders yourself, but what should I use?

A: Basically, you can follow the method described in Effective Go (same as one word, lowercase letters, folder name that makes the packaging clear what you do concisely).

Since this recommendation is the same as the folder name, the same rule is inevitably applied to the folder name. If you want to compose with multiple words, it is common encoding/jsonto divide the folders like this and set the end package as pakcage json.

The package is used by default as the symbol name to use after importing. The simpler and shorter the program, the shorter the program. Go’s practice is to make memory recognition as short as possible, as opposed to Java’s practice of using as explicit a name as possible. Also, if the folder name is different, the importsentence and the symbol used in the program will be different , which will be a problem when reading the code.

However, there are two cases where this one word is not followed.

Test package

For example, suppose slicesyou create a folder named, pakcage slicesand write code in a package named. Normally, in the case of Go, all files in the same folder must be in the same package, _testbut package slices_testonly the name ending with (here ) can be specially set.

_testYou can write common tests for testing that are not included in the released library, or you can write unit tests themselves in this package. However, in this case, slicesit will be treated as a package different from the main body, so slicesyou will not be able to access the functions and structures provided without writing an import statement, and you will only be able to access the public ones. On the contrary, it is an advantage for black box tests such as example tests, but it is not possible to test private elements.

xxxx-go, go-xxxx, xxxx.go folders

This is a case that I sometimes see. You can see it in some off-the-shelf library Go wrappers or Go ports. For example, go-lxc provided by the lxc developer itself has go- to distinguish it from the lxc of the main body in the same layer of GitHub.

Note that hyphens and periods cannot be used in package names. In this case package xxxx, the package name is often given the name without the -go, go-, or .go part, as in.

Build environment / tools

Q: If you look into Go, you’ll find a lot of tools, but what do you really need?

Please tell us about the role of each tool, the advantages of including it, and the disadvantages of not including it.

A: For the time being, only go fmt should be set to be executed when the editor is saved.

  • go fmt: A genuine tool to set the code style to the standard style. Python black or JS / TS prettier in other languages. Trouble with git merging is reduced. If you do not do it, conflicts may increase.
  • go vet: A genuine tool that can compile, but finds potential problems with static analysis. From Go 1.10, it will be executed together with the unit test, so you can benefit from doing nothing (of course you are testing, right?)
  • Other tools: Most of them basically use static checks to find errors. There are also tools that check these tools together .

Go is a compiled language in the first place, so weird code can be found by building it. You can also see various types of consistency. Even if you don’t put anything in it, the starting point is quite high and there is also go vet automatic execution, so you can write code with much more peace of mind than fighting with a manual empty fist in other dynamic languages.

If you want to check more than that, I think you should put it in.

document

Q: I’ve heard that Go has a lot of documentation, but I don’t know how to approach the features I want to use by looking at the reference.

Even if there is a function that seems to be useful, I can not imagine how to use it even if I read the document. I just find sample code such as Qiita. Also, I don’t know how it is sorted, so it’s hard to find.

A: It’s easier to read if you know both the factory function and the interface.

First, when using the structure itself, Go uses it without initializing anything, or initializes it using a factory function. For example, sync WaitGroup and RWMutex work fine with zero initialization. On the other hand, those that need to be initialized are initialized using the factory function. It works even with zero initialization, but some have factory functions for user convenience.

The factory function (which returns a pointer to the struct) will be put in the method list of the struct by go doc. So, when you say “I want to use this structure”, first find the factory function, and that is the clue to the solution.

// Zero initialization
wg: = & sync.WaitGroup {}

// Initialize with factory function
f, _: = os.Create ( "new.zip" )
w: = zip.NewWriter (f)

However, there are some cases where the go doc function of “arranging factory functions” becomes obsolete and difficult to read. Get / Post of net / http is a function that uses it alone for HTTP access, but it has been listed as a factory function of Response. It’s a little different from the user’s feeling, isn’t it? It is sorted in the order of functions and structs, and it is easy to look only for functions that can be used independently, but there is a possibility that functions that can be used for factory methods of structs are also hidden.

Next is the interface. For example, zip.Writerif you want to use the previous io.Writerone, you know that you need something like that. In, io.Writeralso look at, not know what to make with the good, here becomes helpless, it is Arigachi in the Go for that. As I get more knowledge, I understand that "It's OK if you create it with os.Create, and use bytes.Buffer for testing, but it's easy to get caught here.

If you run go doc locally and perform static analysis, you can also find a list of structures that implement the interface. The external input / output system provided by Go as standard can be covered by this, but I think that io.Reader / io.Writer and other areas need to be memorized to some extent.

But some sortpackages , for example, sort.Interfaceexpect the user to implement that interface (so there is no function to create that interface). Also, some arguments may be interfaces, assuming that only the structures provided by the library will come. Whether you create it or use the structure provided by the library, the library provider should provide a document with sample code that works properly. In some cases, you may need to read the test code of the source code.

Even though the culture is rich in documentation, it is unavoidable that there are differences, easy-to-understand, and difficult-to-understand depending on the writer.

Type / variable

Q: I’m developing a web application, but I don’t see the benefits of types

It is troublesome because it takes a lot of time and effort to implement a structure such as a type for JSON mapping.

A: Certainly, the easiest way to experience the benefits of molds is when using something written by someone else. If you use what you wrote yourself, it may be difficult to feel the benefits, but it will be an insurance that will be saved later.

Especially when you come to Go from JavaScript, the current Visual Studio Code is too smart and you can infer without defining type information, so there are times when Go feels troublesome. But it will definitely help you later.

  • Type information can be a hint when reading code written by others. If you enter using an editor such as Visual Studio Code or GoLand, you can use a function called “jump to definition source”. Go properly determines all types, so you can be confident that you can jump to the definition source (but you can’t jump from the interface to the implementation struct).
  • Type information can be a hint when you read your code more than a month later.
  • When navigating around for code cleanup, the editor will tell you an error on the fly if there is a discrepancy. It makes it easier to modify existing code.

Also, if you get older and lose your memory, have a cold, or have a hard hangover, your short-term memory will decline. It might be a good idea to drink a few glasses of beer first and then write the code (absolutely no).

As a bonus, if you want to create a JSON-to-struct mapping, you can use a tool like JSON to Go .

Q: I don’t understand the pointer symbol

*Bet &is to use and does not know if there.

A: It is important to first distinguish between a pointer and an instance (entity).

An instance is the body of data reserved in memory. A 100-byte character string consumes 100 bytes of memory. Pointers, on the other hand, are instance location information. If it is a 64-bit machine, it is 8 bytes.

If the instance is in memory, there is always one address in that memory, so you can create a pointer from the instance. You can also retrieve an instance from a pointer because the pointer points to a specific address. Being able to convert to each other is an important characteristic.

&Is the operation to retrieve the pointer from the instance. Of the code below, &is attached to the bottom. It takes a pointer and puts it in a variable after creating an instance in memory.

// personI contains an instance
personI: = Person {
Name: "small animal" ,
}
// personP creates an instance, then takes out a pointer and stores it
personP: = & Person {
Name: "Test" ,
}

*Has two meanings. The first is an "operation" that retrieves an instance from a pointer. &The opposite operation of.

var name = "Luci" 
// nameP is a pointer
var nameP = & name

// If you display it as it is, the pointer value will be displayed
fmt.Println (nameP) // 0x40c128
// It will be displayed properly when you return to the instance with
* fmt.Println (* nameP) // Luci

The other is a type that represents a pointer. It is the type of variable and argument.

var person Person // person contains an instance of the Person structure 
var person * Person // person contains a pointer to an instance of the Person structure

There is another symbol for pointers. That is .. Structures are used to access members of an interface, but in this case they have the special property of being "usable" regardless of whether they are pointers or instances. In the case of C / C ++, ->I used to access the pointer members, but Go is .OK with both .

Q: :=the =proper use of do not know

There are two symbols for substitution, but I’m always worried about how to use them properly.

A: The editor will tell you what you need. Follow the editor.

If you want to create a variable by explicitly specifying the type =, use using var . :=Writing here will result in an error.

// The right side is a character string, but I want to make it interface {} 
var name interface {} = "small, medium and large"

:=Use Trying to declare and assign at the same time without a variable declaration . =Writing here will result in an error.

=Use when assigning to an existing variable . :=Writing here will result in an error.

If you make a mistake, the compiler will tell you, and the editor and IDE will also draw a red line, so it’s easy to move your hand before you worry.

Be careful when creating a new scope. The following code is the symbol of the place of the if statement :=but =will work but. The conditional clause of if is in the new scope, so duplicating a new variable will not result in an error. Also, if there is a variable with the same name in the parent scope, =it will still work (however, the variable on the parent side will be rewritten).

package main

Q: What does it mean to include the variable name in the return value declaration?

There is a notation to put the variable name in the declaration of the return value, but it becomes long horizontally and I do not feel the merit. What are the benefits?

A: It is the same as accessing the method argument by name without accessing it at the nth, and it is for telling the user and implementer the meaning of the return value.

In particular, when data is read from the outside, but there are many data, rows, columns, errors and return values, the return statement of the program becomes difficult to understand when the number increases. The documentation is also easier to read.

Since the named return value is initialized with a zero value at the start of the function, the interface and pointer such as an empty string for a character string, zero for a numeric type, false for a bool type, and error will be nil. If no error occurs, just return it and there is no problem.

Q: Some function arguments do not have a type name written in them. How should I interpret them?

func Func(a, b, c []byte)There was a declaration like. What are the types of a and b?

A: In Go, the type declared at the end is automatically entered for the omitted argument.

Isn’t there a lot of people who feel uncomfortable when the following declaration is made in the variable declaration? It’s OK if you think that this can also be used at the argument. Of course, if the last variable is not declared, an error will occur.

var a, b int

Q: I want immutable coding, what should I do?

By declaring that it cannot be changed in recent programming languages, it is easier to debug, and I would like to do it in Go as well.

A: Go doesn’t have much immutable realization. Please give up.

TypeScript constis prohibited from reassignment, so it was quite easy to use. constIt mechanically approaches the immutable style by aligning the variable declarations to all . Go constcan be used for primitives such as integers and strings, but not for slices, arrays, maps, struct instances, struct pointers, etc.

Also, maps, slices, etc. are slow to copy every time you change some elements, so you’ll be hit by a barrage of code reviews.

If you make the receiver of the method of the structure an instance instead of a pointer, the changed contents will not be propagated to the instance, so there is a function that can prevent unexpected changes (but this also does not change with the intention of changing it). Note that the behavior will be difficult to understand).

syntax

Q: I want to use the ternary operator

I want to use the ternary operator for conditional initialization processing.

A: Go doesn’t have it, so please write an if statement.

Literal slice map

Q: Doesn’t implicit type conversion like “sss” + 1

In other languages, even if you combine strings and numbers, they will be converted properly. In the case of Go, it is inconvenient not only to combine strings and numbers, but also to calculate integers and decimals as an error.

A: Implicit type conversion can cause unexpected bugs, so it’s Go’s idea to write everything explicitly. So this is not feasible.

fmt.SprintfConvert to a string with

If the result is a string, it fmt.Sprintf's easy to use. %vWill convert any type as it is. If you need detailed specifications, you can specify them using other flags.

fmt.Sprintf ( "% v% v" , "abc" , 1 ) 
// abc1

strconvUse packages for strings → numbers, numbers → strings

The strconv package defines various functions for mutual conversion between strings and other primitive types. FormatFunctions starting with are converted to strings, Parseand functions starting with are converted from strings. fmt.SprintfThe code tends to be longer than that, but you can expect higher performance here.

Make a number with the cast

Cast conversions between numeric types. It is up to the implementer to choose responsibly, considering what the error will be.

price: = 1000
taxRate: = 0.08
totalPrice: = int ( float64 (price) * taxRate)

Logging

Q: How is the log output with the log level set realized?

Is it possible to separate logs such as info / warn in Java’s Log4J and Python’s logging packages? What should I do with Go?

A: Not supported by Go’s standard library. It’s a good idea to use a third-party logging library such as logrus or zap .

Previously, logrus was almost the strongest, but zap, which claims high performance, is also becoming more popular. Since zap specializes in structured logs, it is a good idea to choose one according to your needs. Since zap can also set the sampling rate etc., it is easy to deal with the case where there are too many logs in the production environment and you are in trouble.

Q: Logs are harder to see than Chrome

A: The Chrome developer console is overwhelmingly better than the debugging environment for most programming languages, so give it up.

Database

Q: transaction control of DB is database/sqlthe Begin()use it?

Ultimately, this method will control the transaction, whether directly or indirectly.

sqlx also Begin()uses internally, and gorm also BeginTx()uses the sql package . Even if you use the convenience library, you will eventually database/sqlreach.

Get an email whenever Aman Khanakia publishes.

By signing up, you will create a Medium account if you don’t already have one. Review our Privacy Policy for more information about our privacy practices.

Medium sent you an email at to complete your subscription.

https://www.khanakia.com/

Share your ideas with millions of readers.

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

Step By Step Tutorial in Learning Flutter: My First Flutter Application

Announcing Launch On Pancakeswap — $MRUN Listing And TGE Details

KISS or Not to KISS

Integrating AWS Services with Unity WebGL — (01) Authenticating with Cognito

Getting started with flask | Aishwarya MU

Ti 84 Plus Graphing Calculator User Manual

From the Students’ Perspective

Build and publish multiple RN apps from the same codebase. (part II)

Aman Khanakia

Aman Khanakia

https://www.khanakia.com/

More from Medium

Building Golang Channels From Scratch

Go / Golang Basic Data Types

The Party “Go”ers Dilemma — Sync up for your week-end Party with Go

COPY with Go and PostgreSQL