From b69fa69a8bf53fb4714d96b4daf80fd6de597111 Mon Sep 17 00:00:00 2001
From: Ian Lance Taylor
For a more general introduction to Go, see the Go Tour, How to Write Go Code and Effective Go. +
For a detailed description of the Go language, see the Go spec. +
Go C++ @@ -102,10 +105,12 @@ of the object being declared. The keyword is one ofvar
, exception in that the receiver appears before the name of the object being declared; see the discussion of interfaces. +You can also use a keyword followed by a series of declarations in parentheses. +
var ( @@ -118,6 +123,7 @@ var ( When declaring a function, you must either provide a name for each parameter or not provide a name for any parameter; you can't omit some names and provide others. You may group several names with the same type: +func f(i, j, k int, s, t string) @@ -128,6 +134,7 @@ A variable may be initialized when it is declared. When this is done, specifying the type is permitted but not required. When the type is not specified, the type of the variable is the type of the initialization expression. +var v = *p @@ -137,12 +144,15 @@ var v = *p See also the discussion of constants, below. If a variable is not initialized explicitly, the type must be specified. In that case it will be -implicitly initialized to the type's zero value (0, nil, etc.). There are no +implicitly initialized to the type's zero value +(0
,nil
, etc.). There are no uninitialized variables in Go. +Within a function, a short declaration syntax is available with
:=
. +v1 := v2 @@ -150,6 +160,7 @@ v1 := v2This is equivalent to +
var v1 = v2 @@ -157,6 +168,7 @@ var v1 = v2Go permits multiple assignments, which are done in parallel. +
i, j = j, i // Swap i and j. @@ -166,6 +178,7 @@ i, j = j, i // Swap i and j. Functions may have multiple return values, indicated by a list in parentheses. The returned values can be stored by assignment to a list of variables. +func f() (i int, j int) { ... } @@ -180,22 +193,27 @@ incomplete (the exact rules are in the language specification). A consequence of this is that in some cases Go does not permit you to use a line break. For example, you may not write +func g() { // INVALID }+A semicolon will be inserted after
g()
, causing it to be a function declaration rather than a function definition. Similarly, you may not write +if x { } else { // INVALID }+A semicolon will be inserted after the
}
preceding theelse
, causing a syntax error. +Since semicolons do end statements, you may continue using them as in @@ -203,6 +221,7 @@ C++. However, that is not the recommended style. Idiomatic Go code omits unnecessary semicolons, which in practice is all of them other than the initial
for
loop clause and cases where you want several short statements on a single line. +While we're on the topic, we recommend that rather than worry about @@ -211,12 +230,14 @@ the
gofmt
program. That will produce a single standard Go style, and let you worry about your code rather than your formatting. While the style may initially seem odd, it is as good as any other style, and familiarity will lead to comfort. +When using a pointer to a struct, you use
.
instead of->
. Thus syntactically speaking a structure and a pointer to a structure are used in the same way. +type myStruct struct { i int } @@ -230,6 +251,7 @@ Go does not require parentheses around the condition of anif
statement, or the expressions of afor
statement, or the value of aswitch
statement. On the other hand, it does require curly braces around the body of anif
orfor
statement. +if a < b { f() } // Valid @@ -245,18 +267,21 @@ Go does not have awhile
statement nor does it have a statement. Thefor
statement may be used with a single condition, which makes it equivalent to awhile
statement. Omitting the condition entirely is an endless loop. +Go permits
break
andcontinue
to specify a label. The label must refer to afor
,switch
, orselect
statement. +In a
switch
statement,case
labels do not fall through. You can make them fall through using thefallthrough
keyword. This applies even to adjacent cases. +switch i { @@ -268,6 +293,7 @@ case 1:But a
case
can have multiple values. +switch i { @@ -282,6 +308,7 @@ any type that supports the equality comparison operator, such as strings or pointers, can be used—and if theswitch
value is omitted it defaults totrue
. +switch { @@ -299,10 +326,12 @@ The++
and--
operators may only be used in statements, not in expressions. You cannot writec = *p++
.*p++
is parsed as(*p)++
. +The
defer
statement may be used to call a function after the function containing thedefer
statement returns. +fd := open("filename") @@ -320,6 +349,7 @@ A value derived from an untyped constant becomes typed when it is used within a context that requires a typed value. This permits constants to be used relatively freely without requiring general implicit type conversion. +var a uint @@ -330,6 +360,7 @@ f(a + 1) // untyped numeric constant "1" becomes typed as uint The language does not impose any limits on the size of an untyped numeric constant or constant expression. A limit is only applied when a constant is used where a type is required. +const huge = 1 << 100 @@ -342,6 +373,7 @@ Go does not support enums. Instead, you can use the special name series of increasing value. When an initialization expression is omitted for aconst
, it reuses the preceding expression. +const ( @@ -362,40 +394,43 @@ The builtinlen
function returns the length of the slice. The builtincap
function returns the capacity. +Given an array, or another slice, a new slice is created via -
a[I:J]
. This +a[i:j]
. This creates a new slice which refers toa
, starts at -indexI
, and ends before index -J
. It has lengthJ - I
. +indexi
, and ends before index +j
. It has lengthj-i
. +Ifi
is omitted, the slice starts at0
. +Ifj
is omitted, the slice ends atlen(a)
. The new slice refers to the same array to whicha
refers. That is, changes made using the new slice may be seen usinga
. The capacity of the new slice is simply the capacity ofa
minus -I
. The capacity -of an array is the length of the array. You may also assign an array pointer -to a variable of slice type; givenvar s []int; var a[10] int
, -the assignments = &a
is equivalent to -s = a[0:len(a)]
. +i
. The capacity +of an array is the length of the array. +What this means is that Go uses slices for some cases where C++ uses pointers. If you create a value of type
[100]byte
(an array of 100 bytes, perhaps a buffer) and you want to pass it to a function without copying it, you should -declare the function parameter to have type[]byte
, and pass the -address -of the array. Unlike in C++, it is not +declare the function parameter to have type[]byte
, and +pass a slice of the array (a[:]
will pass the entire array). +Unlike in C++, it is not necessary to pass the length of the buffer; it is efficiently accessible vialen
. +The slice syntax may also be used with a string. It returns a new string, whose value is a substring of the original string. Because strings are immutable, string slices can be implemented without allocating new storage for the slices's contents. +
Making values
@@ -408,6 +443,33 @@ initializes it with the value0
, and returns its address, which has type*int
. Unlike in C++,new
is a function, not an operator;new int
is a syntax error. + + ++Perhaps surprisingly,
+ +new
is not commonly used in Go +programs. In Go taking the address of a variable is always safe and +never yields a dangling pointer. If the program takes the address of +a variable, it will be allocated on the heap if necessary. So these +functions are equivalent: ++type S { I int } + +func f1() *S { + return new(S) +} + +func f2() *S { + var s S + return &s +} + +func f3() *S { + // More idiomatic: use composite literal syntax. + return &S{0} +} +Map and channel values must be allocated using the builtin function @@ -424,6 +486,7 @@ a map type takes an optional argument which is the expected capacity of the map. Calling
make
with a channel type takes an optional argument which sets the buffering capacity of the channel; the default is 0 (unbuffered). +The
make
function may also be used to allocate a slice. @@ -435,6 +498,7 @@ A second, optional, argument is the capacity of the slice. For example,new([20]int)[0:10]
. Since Go uses garbage collection, the newly allocated array will be discarded sometime after there are no references to the returned slice. +Interfaces
@@ -447,33 +511,38 @@ Go, any type which provides the methods named in the interface may be treated as an implementation of the interface. No explicitly declared inheritance is required. The implementation of the interface is entirely separate from the interface itself. +A method looks like an ordinary function definition, except that it has a receiver. The receiver is similar to the
this
pointer in a C++ class method. +type myType struct { i int } -func (p *myType) get() int { return p.i } +func (p *myType) Get() int { return p.i }-This declares a method
get
associated withmyType
. +This declares a methodGet
associated withmyType
. The receiver is namedp
in the body of the function. +Methods are defined on named types. If you convert the value to a different type, the new value will have the methods of the new type, not the old type. +
You may define methods on a builtin type by declaring a new named type derived from it. The new type is distinct from the builtin type. +
type myInteger int -func (p myInteger) get() int { return int(p) } // Conversion required. +func (p myInteger) Get() int { return int(p) } // Conversion required. func f(i int) { } var v myInteger // f(v) is invalid. @@ -482,58 +551,64 @@ var v myIntegerGiven this interface: +
type myInterface interface { - get() int - set(i int) + Get() int + Set(i int) }we can make
myType
satisfy the interface by adding +-func (p *myType) set(i int) { p.i = i } +func (p *myType) Set(i int) { p.i = i }Now any function which takes
myInterface
as a parameter will accept a variable of type*myType
. +-func getAndSet(x myInterface) {} +func GetAndSet(x myInterface) {} func f1() { var p myType - getAndSet(&p) + GetAndSet(&p) }In other words, if we view
myInterface
as a C++ pure abstract base -class, definingset
andget
for +class, definingSet
andGet
for*myType
made*myType
automatically inherit frommyInterface
. A type may satisfy multiple interfaces. +An anonymous field may be used to implement something much like a C++ child class. +
type myChildType struct { myType; j int } -func (p *myChildType) get() int { p.j++; return p.myType.get() } +func (p *myChildType) Get() int { p.j++; return p.myType.Get() }This effectively implements
myChildType
as a child ofmyType
. +func f2() { var p myChildType - getAndSet(&p) + GetAndSet(&p) }@@ -544,8 +619,9 @@ methods associated with the anonymous field are promoted to become methods of the enclosing type. In this case, becausemyChildType
has an anonymous field of typemyType
, the methods ofmyType
also become methods ofmyChildType
. -In this example, theget
method was -overridden, and theset
method was inherited. +In this example, theGet
method was +overridden, and theSet
method was inherited. +This is not precisely the same as a child class in C++. @@ -553,21 +629,23 @@ When a method of an anonymous field is called, its receiver is the field, not the surrounding struct. In other words, methods on anonymous fields are not virtual functions. When you want the equivalent of a virtual function, use an interface. +
-A variable which has an interface type may be converted to have a +A variable that has an interface type may be converted to have a different interface type using a special construct called a type assertion. This is implemented dynamically at run time, like C++
dynamic_cast
. Unlikedynamic_cast
, there does not need to be any declared relationship between the two interfaces. +type myPrintInterface interface { - print() + Print() } func f3(x myInterface) { - x.(myPrintInterface).print() // type assertion to myPrintInterface + x.(myPrintInterface).Print() // type assertion to myPrintInterface }@@ -576,11 +654,13 @@ The conversion tomyPrintInterface
is entirely dynamic. It will work as long as the underlying type of x (the dynamic type) defines aBecause the conversion is dynamic, it may be used to implement generic programming similar to templates in C++. This is done by manipulating values of the minimal interface. +
type Any interface { } @@ -593,16 +673,24 @@ values of the contained type. As the typing is dynamic rather than static, there is no equivalent of the way that a C++ template may inline the relevant operations. The operations are fully type-checked at run time, but all operations will involve a function call. +-type iterator interface { - get() Any - set(v Any) - increment() - equal(arg *iterator) bool +type Iterator interface { + Get() Any + Set(v Any) + Increment() + Equal(arg Iterator) bool }++Note that
+Equal
has an argument of +typeIterator
. This does not behave like a C++ +template. See the +FAQ. +Goroutines
@@ -611,18 +699,20 @@ using the
go
statement. Thego
statement runs a function in a different, newly created, goroutine. All goroutines in a single program share the same address space. +Internally, goroutines act like coroutines that are multiplexed among multiple operating system threads. You do not have to worry about these details. +
func server(i int) { - for { - print(i) - sys.sleep(10) - } + for { + fmt.Print(i) + time.Sleep(10 * time.Second) + } } go server(1) go server(2) @@ -631,13 +721,16 @@ go server(2)(Note that the
for
statement in theserver
function is equivalent to a C++while (true)
loop.) +Goroutines are (intended to be) cheap. +
Function literals (which Go implements as closures) can be useful with the
go
statement. +var g int @@ -658,21 +751,23 @@ operator. To receive a value on a channel, use<-
as a unary operator. When calling functions, channels are passed by reference. +The Go library provides mutexes, but you can also use a single goroutine with a shared channel. Here is an example of using a manager function to control access to a single value. +
-type cmd struct { get bool; val int } -func manager(ch chan cmd) { - var val int = 0 +type Cmd struct { Get bool; Val int } +func Manager(ch chan Cmd) { + val := 0 for { - c := <- ch - if c.get { c.val = val; ch <- c } - else { val = c.val } + c := <-ch + if c.Get { c.Val = val; ch <- c } + else { val = c.Val } } }@@ -684,26 +779,28 @@ with the manager at once: a goroutine waiting for a response from the manager might receive a request from another goroutine instead. A solution is to pass in a channel. +-type cmd2 struct { get bool; val int; ch <- chan int } -func manager2(ch chan cmd2) { - var val int = 0 +type Cmd2 struct { Get bool; Val int; Ch <- chan int } +func Manager2(ch chan Cmd2) { + val := 0 for { - c := <- ch - if c.get { c.ch <- val } - else { val = c.val } + c := <-ch + if c.Get { c.ch <- val } + else { val = c.Val } } }-To use
manager2
, given a channel to it: +To useManager2
, given a channel to it: +-func f4(ch <- chan cmd2) int { +func f4(ch <- chan Cmd2) int { myCh := make(chan int) - c := cmd2{ true, 0, myCh } // Composite literal syntax. + c := Cmd2{ true, 0, myCh } // Composite literal syntax. ch <- c return <-myCh } -- 2.48.1