(This is an unofficial Go FAQ. The official one is here.)
non-name *** on left side of :=
mean?unexpected newline, expecting { after if clause
mean?declared and not used
mean?new(T)
a sugar of var t T; (&t)
?all goroutines are asleep - deadlock
mean?time.Sleep(d)
and the channel receive operation <-time.After(d)
?TrimLeft
and TrimRight
functions in the strings
and bytes
standard packages often return unexpected results, are there bugs in these function implementations?fmt.Print
and fmt.Println
functions?log.Print
and log.Println
functions?fmt.Print
, fmt.Println
and fmt.Printf
functions synchronized?print
/println
functions and the corresponding print functions in the fmt
and log
standard packages?math/rand
standard package and the crypto/rand
standard package?math.Round
function?nil
values equal sometimes?[]T1
and []T2
share the same underlying type
even if the two different types T1
and T2
share the same underlying type?T
,
why is the method set of *T
always a super set of the method set of T
,
but not vice versa?set
container type?[]byte
and []rune
values to strings?non-name *** on left side of :=
mean?
:=
must be pure
identifiers and at least one of them must be a new variable name.
This means container elements (x[i]
),
struct fields (x.f
), pointer dereferences (*p
)
and qualified identifiers (aPackage.Value
)
can't appear at the left side of :=
.
Currently, there is an open issue (which was merged with a more related one) for this problem. It looks Go core team wants to leave this problem unresolved currently.
unexpected newline, expecting { ...
mean?
In Go, we can't break a code line at an arbitrary position. Please read line break rules in Go for details. By the rules, generally, it is not okay to break code lines just before the open brackets.
For example, the following codeif true
{
}
for i := 0; i < 10; i++
{
}
var _ = []int
{
1, 2, 3
}
will be interpreted as
if true;
{
}
for i := 0; i < 10; i++;
{
}
var _ = []int;
{
1, 2, 3;
}
Go compilers will report an error for each open bracket {
.
To avoid these errors, we should rewrite the above code as the following.
if true {
}
for i := 0; i < 10; i++ {
}
var _ = []int {
1, 2, 3,
}
declared and not used
mean?
For the standard Go compiler, each variable declared in local code blocks must be used as a r-value (right-hand-side value) for at least once.
So the following code fails to compile.func f(x bool) {
var y = 1 // y declared but not used (as r-values)
if x {
y = 2 // here y is used as a left-hand-side value
}
}
No. Go 1 specification says the iteration order over a map is not specified and is not guaranteed to be the same from one iteration to the next. For the standard Go compiler, the map iteration orders are always partially randomized to varying extent. If you require a stable iteration order for a map you must maintain the order by yourself. Please read Go maps in action for more information.
However, please note, since Go 1.12, the entry order in the print result of the print functions in standard packages are always ordered.
At least for the standard Go compiler and gccgo, the answer is yes. How many bytes will be padded is OS and compiler dependent. Please read memory layouts for details.
Go Compilers will not rearrange struct fields to minimize struct value sizes. Doing this may cause some unexpected results. However, programmers can minimize padding by reordering the fields manually.
In the current standard Go runtime implementation, as long as a memory block is referenced by at least one active pointer, that memory block will not be viewed as garbage and will not be collected.
All the fields of an addressable struct value can be taken addresses. If the size of the final field in a non-zero-sized struct value is zero, then taking the address of the final field in the struct value will return an address which is beyond the allocated memory block for the struct value. The returned address may point to another allocated memory block which closely follows the one allocated for the non-zero-sized struct value. As long as the returned address is stored in an active pointer value, the other allocated memory block will not get garbage collected, which may cause memory leaking.
To avoid these kinds of memory leak problems, the standard Go compiler will ensure that taking the address of the final field in a non-zero-sized struct will never return an address which is beyond the allocated memory block for the struct. The standard Go compiler implements this by padding some bytes after the final zero-sized field when needed.
If the types of all fields in a struct type are zero-sized (so the struct is also a zero-sized type), then there is no need to pad bytes in the struct, for the standard Go compiler treats zero-sized memory blocks specially.
An example:package main
import (
"unsafe"
"fmt"
)
func main() {
type T1 struct {
a struct{}
x int64
}
fmt.Println(unsafe.Sizeof(T1{})) // 8
type T2 struct {
x int64
a struct{}
}
fmt.Println(unsafe.Sizeof(T2{})) // 16
}
new(T)
a sugar of var t T; (&t)
?
Generally we can think so, though there may be some subtle differences between the two, depending on compiler implementations.
The memory block allocated by new
may be either on stack or on heap.
all goroutines are asleep - deadlock
mean?
The word asleep is not accurate here, it means in blocking state in fact.
As a blocking goroutine can only be unblocked by another goroutine, if all goroutines in a program enter blocking state, then all of they will stay in blocking state for ever. This means the program is deadlocked. A normal running program is never expected to be deadlocked, so the standard Go runtime makes the program crash and exit.
The addresses passed to the 64-bit functions in sync/atomic
package
must be 64-bit aligned, otherwise, calls to these functions may panic at run time.
For the standard Go compiler and gccgo compiler, on 64-bit architectures, 64-bit integers are guaranteed to be 64-bit aligned. So they can be always accessed atomically without any problems.
On 32-bit architectures, 64-bit integers are only guaranteed to be 32-bit aligned. So accessing many 64-bit integers atomically may cause panics. However, there are some ways to guarantee some 64-bit integers to be relied upon to be 64-bit aligned. Please read memory layouts in Go for details.
No for the standard Go compiler, even if the sizes of the assigned values are native words.
Please read the official question for more details.
For most types, this is true. In fact, this is compiler dependent. For example, for the standard Go compiler, the statement is wrong for some zero values of string types.
Evidence:package main
import (
"unsafe"
"fmt"
)
func main() {
var s1 string
fmt.Println(s1 == "") // true
fmt.Println(*(*uintptr)(unsafe.Pointer(&s1))) // 0
var s2 = "abc"[0:0]
fmt.Println(s2 == "") // true
fmt.Println(*(*uintptr)(unsafe.Pointer(&s2))) // 4869856
fmt.Println(s1 == s2) // true
}
Inversely, for all the architectures the standard Go compiler currently supports, if all bytes in a value are zero, then the value must be a zero value of its type. However, Go specification doesn't guarantee this. I have heard of that on some very old processors, nil pointers are not zero in memory.
Yes, the standard Go compiler supports inlining functions. The compiler will automatically inline some very short functions which satisfy certain requirements. The specific inline requirements may change from version to version.
-gcflags "-l"
build option disables inlining globally, which will prevent all functions from being inline expanded.
//go:noinline
directive before a function declaration to
prevent the function from being inlined, but this way is not guaranteed to work in the future.
In Go programs, we can set a finalizer function for an object by using
the runtime.SetFinalizer
function.
Generally, the finalizer function will be called before the object is garbage collected.
But finalizers are never intended to be used as destructors of objects.
The finalizers set by runtime.SetFinalizer
are not guaranteed to run.
So you shouldn't rely on finalizers for your program correctness.
The main intention of finalizers is to allow the maintainers of a library to
compensate for problems caused by incorrect library use.
For example, if a programmer uses os.Open
to open
many files but forgets to close them after using them, then the program
will hold many file descriptors until the program exits. This is a classic example of resource leak.
To avoid the program holding too many file descriptors, the maintainers of the
os
package will set a finalizer on the every created os.File
object. The finalizer will close the file descriptor stored in the os.File
object. As mentioned above, the finalizers are not guaranteed to be called.
They are just used to make the extent of resource leak as small as possible.
Please note, some finalizers will never get called for sure, and sometimes setting finalizers improperly will prevent some objects from being garbage collected. Please read the runtime.SetFinalizer function documentation to get more details.
days := time.Date(year, month+1, 0, 0, 0, 0, 0, time.UTC).Day()
For Go time APIs, the usual month range is [1, 12]
and the start day of each month is 1
.
The start time of a month m
in year y
is
time.Date(y, m, 1, 0, 0, 0, 0, time.UTC)
.
The arguments passed to time.Date
can be outside their usual ranges
and will be normalized during the conversion.
For example, January 32 will be converted to February 1.
time.Date
use examples in Go:
package main
import (
"time"
"fmt"
)
func main() {
// 2017-02-01 00:00:00 +0000 UTC
fmt.Println(time.Date(2017, 1, 32, 0, 0, 0, 0, time.UTC))
// 2017-01-31 23:59:59.999999999 +0000 UTC
fmt.Println(time.Date(2017, 1, 32, 0, 0, 0, -1, time.UTC))
// 2017-01-31 00:00:00 +0000 UTC
fmt.Println(time.Date(2017, 2, 0, 0, 0, 0, 0, time.UTC))
// 2016-12-31 00:00:00 +0000 UTC
fmt.Println(time.Date(2016, 13, 0, 0, 0, 0, 0, time.UTC))
// 2017-02-01 00:00:00 +0000 UTC
fmt.Println(time.Date(2016, 13, 32, 0, 0, 0, 0, time.UTC))
}
time.Sleep(d)
and the channel receive operation <-time.After(d)
?
The two will both pause the current goroutine execution for a certain duration.
The difference is the function call time.Sleep(d)
will let the current goroutine enter sleeping sub-state,
but still stay in running state,
whereas, the channel receive operation <-time.After(d)
will let the current goroutine enter blocking state.
TrimLeft
and TrimRight
functions in the strings
and bytes
standard packages often return unexpected results, are there bugs in these function implementations?
Aha, maybe there are bugs in the implementations, but none are confirmed now. If the return results are unexpected, it is more possible that your expectations are not correct.
strings
and bytes
standard packages.
These functions can be categorized into two groups:
Trim
, TrimLeft
, TrimRight
, TrimSpace
, TrimFunc
, TrimLeftFunc
, TrimRightFunc
.
These functions will trim all leading or trailing UTF-8-encoded Unicode code points (a.k.a. runes)
which satisfy the specified or implied conditions (TrimSpace
implies to trim all kinds of white spaces).
Each of the leading or trailing runes will be checked until one doesn't satisfy the specified or implied conditions.
TrimPrefix
, TrimSuffix
.
The two functions will trim the specified prefix or suffix substrings (or subslices) as a whole.
Some
programmers
misused
the
TrimLeft
and TrimRight
functions
as TrimPrefix
and TrimSuffix
functions when they use the trim functions the first time.
Certainly, the return results are very possible not as expected.
package main
import (
"fmt"
"strings"
)
func main() {
var s = "abaay森z众xbbab"
o := fmt.Println
o(strings.TrimPrefix(s, "ab")) // aay森z众xbbab
o(strings.TrimSuffix(s, "ab")) // abaay森z众xbb
o(strings.TrimLeft(s, "ab")) // y森z众xbbab
o(strings.TrimRight(s, "ab")) // abaay森z众x
o(strings.Trim(s, "ab")) // y森z众x
o(strings.TrimFunc(s, func(r rune) bool {
return r < 128 // trim all ascii chars
})) // 森z众
}
fmt.Print
and fmt.Println
functions?
The fmt.Println
function will always write a space between two adjacent arguments,
whereas the fmt.Print
function will write a space between two adjacent arguments
only if both of (the concrete values of) the two adjacent arguments are not strings.
Another difference is that fmt.Println
will write
a newline character in the end,
but the fmt.Print
function will not.
log.Print
and log.Println
functions?
The difference between the log.Print
and log.Println
functions
is the same as the first difference between the fmt.Print
and fmt.Println
functions described in the last question.
Both of the two functions will write a newline character in the end.
fmt.Print
, fmt.Println
and fmt.Printf
functions synchronized?
No, these functions are not synchronized.
Please use the corresponding functions in the log
standard package instead
when synchronizations are needed.
You can call log.SetFlags(0)
to remove the prefix from each log line.
print
/println
functions and the corresponding print functions in the fmt
and log
standard packages?
print
/println
functions
will write to standard error.
The print functions in the fmt
standard package
will write to standard output.
The print functions in the log
standard package
will write to standard error by default,
though this can be changed using the
log.SetOutput
function.
print
/println
functions
can't take array and struct arguments.
print
/println
functions
write the addresses of the underlying value parts of the argument,
whereas the print functions in the fmt
and log
standard packages try to write the value literal of the dynamic values of the interface arguments.
print
/println
functions
will not make the values referenced by the arguments of the calls
escape to heap, whereas the print functions in the fmt
and log
standard packages will.
String() string
or Error() string
method, the print functions in the fmt
and log
standard packages will try to call that method when writing the argument,
whereas the built-in print
/println
functions
will ignore methods of arguments.
print
/println
functions
are not guaranteed to exist in future Go versions.
math/rand
standard package and the crypto/rand
standard package?
The pseudo random numbers produced by the math/rand
standard
package are deterministic for a given seed.
The produced random numbers are not good for security-sensitive contexts.
For cryptographical security purpose, we should use the pseudo random numbers
produced by the crypto/rand
standard package.
math.Round
function?
There is a math.Round
function, but only since Go 1.10.
Two new functions, math.Round
and math.RoundToEven
have been added since Go 1.10.
Before Go 1.10, much time and effort was spent
discussing whether or not
the math.Round
function should be added to standard package or not.
In the end, the proposal was adopted.
Types which don't support comparisons can't be used as the key type of map types.
nil
identifier.
==
will panic at run time if the two dynamic types of the two interface values
are identical and incomparable.
On why slice, map and function types don't support comparison, please read this answer in the official Go FAQ.
nil
values equal sometimes?
(The answer in the official Go FAQ may also answer this question.)
An interface value can be viewed as a box which is used to encapsulate non-interface values.
Only values whose types implement the type of the interface value can be boxed (encapsulated) into the interface value.
In Go, there are several kinds of types whose zero values are represented as the predeclared identifier nil
.
An interface value boxing nothing is a zero interface value, a.k.a, a nil interface value.
However an interface value boxing a nil non-interface value doesn't box nothing, so it is not, and doesn't equal to, a nil interface value.
When comparing a nil interface value and a nil non-interface value (assume they can be compared), the nil non-interface value will be converted to the type of the nil interface value before doing the comparison. The conversion result is an interface value boxing a copy of the non-interface value. The result interface value doesn't box nothing, so it is not, or doesn't equal to, the nil interface value.
Please read interfaces in Go and nils in Go for detailed explanations.
For example:package main
import "fmt"
func main() {
var pi *int = nil
var pb *bool = nil
var x interface{} = pi
var y interface{} = pb
var z interface{} = nil
fmt.Println(x == y) // false
fmt.Println(x == nil) // false
fmt.Println(y == nil) // false
fmt.Println(x == z) // false
fmt.Println(y == z) // false
}
[]T1
and []T2
share the same underlying type
even if the two different types T1
and T2
share the same underlying type?
(It looks the official Go FAQ also added a similar question not long ago.)
In Go, values of a slice type can be converted to another slice type
without using the unsafe
mechanisms only if the two slice types
share the same underlying type.
(This article
lists the full list of value conversion rules.)
The underlying type of an unnamed composite type is the composite type itself.
So even if two different types T1
and T2
share the same underlying type,
type []T1
and []T2
are still different types,
so their underlying types are also different, which means values of one of them can't be converted
to the other.
[]T1
and []T2
are not same are:
[]T1
and []T2
to each other is not strong in practice.
The same reasons are also valid for other composite types.
For example, type map[T]T1
and map[T]T2
also don't share the same underlying type
even if T1
and T2
share the same underlying type.
[]T1
can be converted to
[]T2
by using the unsafe
mechanisms,
but generally this is not recommended:
package main
import (
"fmt"
"unsafe"
)
func main() {
type MyInt int
var a = []int{7, 8, 9}
var b = *(*[]MyInt)(unsafe.Pointer(&a))
b[0]= 123
fmt.Println(a) // [123 8 9]
fmt.Println(b) // [123 8 9]
fmt.Printf("%T \n", a) // []int
fmt.Printf("%T \n", b) // []main.MyInt
}
&T{}
, in Go.
It is a short form of tmp := T{}; (&tmp)
.
However, though &T{}
is legal,
the literal T{}
is still not addressable.
The first reason is that it would conflict with maps' internal memory management process. In Go, a map is designed as a container which can contain an unlimited number of entries if memory is available. To ensure good map element indexing efficiency, in the official Go runtime implementation each map value only maintains one continuous memory segment for the entirety of entries stored in that map. Therefore, Go runtime needs to allocate larger memory segments for a map from time to time when more and more entries are being put into the map. In the process, the entries stored on older memory segments will be moved to newer memory segments. There might be also some other reasons causing memory movements of entries. In other words, the addresses of map elements will change from time to time on need. If map elements are allowed to have their addresses taken, then when some map entries are moved, Go runtime would have to update all pointers which are storing the addresses of the moved elements, which brings many difficulties in implementing Go compilers and runtimes and greatly decreases execution performance. So, currently, map elements cannot have their addresses taken.
Secondly, the map index expression aMap[key]
might
return an element stored in map aMap
or not, which means aMap[key]
might still result
in a zero value after (&aMap[key]).Modify()
is called. This would confuse many people. (Here Modify()
refers to a hypothetical method which would modify the value aMap[key]
).
struct {
// elements references an element sequence.
elements unsafe.Pointer
length int
capacity int
}
Each slice indirectly references an underlying element sequence internally. Although a non-nil slice is not addressable, its internal element sequence is always allocated somewhere and must be addressable. Taking addresses of elements of a slice is taking the addresses of elements of the internal element sequence actually. This is why elements of unaddressable non-nil slices are always addressable.
T
,
why is the method set of *T
always a super set of the method set of T
,
but not vice versa?
A value of type T
can call methods of type *T
,
but only if the value of T
is addressable.
Compilers will take the address of the T
value automatically
before calling the pointer receiver methods.
Because type T
can have values that are not addressable,
not all values of type T
are capable of calling methods of type *T
.
This convenience is just a sugar, not an intrinsic rule.
A value of type *T
can always call methods of type T
.
This is because it is always legal to dereference a pointer value.
This convenience is not only a sugar, but also an intrinsic rule.
So, it makes sense that the method set of *T
is always
a super set of the method set of T
, but not vice versa.
T
,
an implicit method with the same name and the same signature is automatically
declared on type *T
.
Please read methods for details.
func (t T) MethodX(v0 ParamType0, ...) (ResultType0, ...) {
...
}
// An implicit method of *T is automatically defined as
func (pt *T) MethodX(v0 ParamType0, ...) (ResultType0, ...) {
return (*pt).MethodX(v0, ...)
}
Please read this answer in the official Go FAQ to get more explanations.
Please read methods in Go for details.
In Go, up to now (Go 1.20), there are no values satisfy the third definition. In other words, the third definition is not supported.
Name constant values satisfy the first definition.
Methods and package-level functions can also viewed as declared immutable values. They satisfy the second definition. String elements (bytes) also satisfy the second definition.
There are no ways to declare other custom immutable named values in Go.
set
container type?
map[Tkey]struct{}
is often used as a set type.
[]byte
and []rune
values to strings?
In Go, byte
is an alias of type uint8
.
In other words, byte
and uint8
are the same identical type.
The same relation is for rune
and int32
.
A rune
often is used to store a Unicode code point.
[]byte
and []rune
values can be explicitly and directly converted to strings,
and vice versa.
package main
import "fmt"
func main() {
var s0 = "Go"
var bs = []byte(s0)
var s1 = string(bs)
var rs = []rune(s0)
var s2 = string(rs)
fmt.Println(s0 == s1) // true
fmt.Println(s0 == s2) // true
}
About more on strings, please read strings in Go.
import (
"unsafe"
"sync/atomic"
)
type T int // just a demo
var p *T
func demo(newP *T) {
// load
var _ = (*T)(atomic.LoadPointer(
(*unsafe.Pointer)(unsafe.Pointer(&p)),
))
// store
atomic.StorePointer(
(*unsafe.Pointer)(unsafe.Pointer(&p)),
unsafe.Pointer(newP),
)
// swap
var oldP = (*T)(atomic.SwapPointer(
(*unsafe.Pointer)(unsafe.Pointer(&p)),
unsafe.Pointer(newP),
))
// compare and swap
var swapped = atomic.CompareAndSwapPointer(
(*unsafe.Pointer)(unsafe.Pointer(&p)),
unsafe.Pointer(oldP),
unsafe.Pointer(newP),
)
_ = swapped
}
Yes, now it is very verbose to use the pointer atomic functions.
iota
mean?
iota
is used in constant declarations.
In each constant declaration group, its value is N
in the Nth constant specification in that constant declaration group.
This allows for easy declaration of related constants.
closed
function to check whether or not a channel is closed?
The reason is that the usefulness of such function would be very limited, while the potential for misuse is high. The return result of a call to such function may be not able to reflect the latest status of the input channel argument. So, it is not a good idea to make decisions relying on the return result.
If you do need such a function, it would be effortless to write one by yourself.
Please read this article
to get how to write closed
functions and how to avoid using such a function.
Yes, it is absolutely safe in Go.
Go compilers which support stack will do escape analysis. For the standard Go compiler, if the escape analyzer thinks a memory block will only be used in the current goroutine for sure, it will allocate the memory block on stack. If not, the memory block will be allocated on the heap. Please read memory block for more information.
In the Go community, a gopher means a Go programmer. This nickname may originate from the fact that Go language adopted a cartoon gopher as the mascot. BTW, the cartoon gopher is designed by Renee French, who is the wife of the (first) Go project leader, Rob Pike.
The Go 101 프로젝트는 Github 에서 호스팅됩니다. 오타, 문법 오류, 부정확한 표현, 설명 결함, 코드 버그, 끊어진 링크와 같은 모든 종류의 실수에 대한 수정 사항을 제출하여 Go 101을 개선을 돕는 것은 언제나 환영합니다.
주기적으로 Go에 대한 깊이 있는 정보를 얻고 싶다면 Go 101의 공식 트위터 계정인 @go100and1을 팔로우하거나 Go 101 슬랙 채널에j가입해주세요.
reflect
표준 패키지sync
표준 패키지sync/atomic
표준 패키지