From 5ff4c17907d5b19510a62e08fd8d3b11e62b431d Mon Sep 17 00:00:00 2001 From: Ondřej Surý Date: Tue, 13 Sep 2011 13:13:40 +0200 Subject: Imported Upstream version 60 --- doc/go_for_cpp_programmers.html | 707 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 707 insertions(+) create mode 100644 doc/go_for_cpp_programmers.html (limited to 'doc/go_for_cpp_programmers.html') diff --git a/doc/go_for_cpp_programmers.html b/doc/go_for_cpp_programmers.html new file mode 100644 index 000000000..7168f1d05 --- /dev/null +++ b/doc/go_for_cpp_programmers.html @@ -0,0 +1,707 @@ + + +

+Go is a systems programming language intended to be a general-purpose +systems language, like C++. +These are some notes on Go for experienced C++ programmers. This +document discusses the differences between Go and C++, and says little +to nothing about the similarities. + +

+For a more general introduction to Go, see the +Go tutorial and +Effective Go. + +

+For a detailed description of the Go language, see the +Go spec. + +

Conceptual Differences

+ + + +

Syntax

+ +

+The declaration syntax is reversed compared to C++. You write the name +followed by the type. Unlike in C++, the syntax for a type does not match +the way in which the variable is used. Type declarations may be read +easily from left to right. + +

+Go                           C++
+var v1 int                // int v1;
+var v2 string             // const std::string v2;  (approximately)
+var v3 [10]int            // int v3[10];
+var v4 []int              // int* v4;  (approximately)
+var v5 struct { f int }   // struct { int f; } v5;
+var v6 *int               // int* v6;  (but no pointer arithmetic)
+var v7 map[string]int     // unordered_map<string, int>* v7;  (approximately)
+var v8 func(a int) int    // int (*v8)(int a);
+
+ +

+Declarations generally take the form of a keyword followed by the name +of the object being declared. The keyword is one of var, +func, +const, or type. Method declarations are a minor +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 (
+    i int
+    m float64
+)
+
+ +

+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)
+
+ +

+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
+
+ +

+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 +uninitialized variables in Go. + +

+Within a function, a short declaration syntax is available with +:= . + +

+v1 := v2
+
+ +

+This is equivalent to + +

+var v1 = v2
+
+ +

+Go permits multiple assignments, which are done in parallel. + +

+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) { ... }
+v1, v2 = f()
+
+ +

+Go code uses very few semicolons in practice. Technically, all Go +statements are terminated by a semicolon. However, Go treats the end +of a non-blank line as a semicolon unless the line is clearly +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 +the else, causing a syntax error. + +

+Since semicolons do end statements, you may continue using them as in +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 +semicolons and brace placement, you format your code with +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 }
+var v9 myStruct              // v9 has structure type
+var p9 *myStruct             // p9 is a pointer to a structure
+f(v9.i, p9.i)
+
+ +

+Go does not require parentheses around the condition of a if +statement, or the expressions of a for statement, or the value of a +switch statement. On the other hand, it does require curly braces +around the body of an if or for statement. + +

+if a < b { f() }             // Valid
+if (a < b) { f() }           // Valid (condition is a parenthesized expression)
+if (a < b) f()               // INVALID
+for i = 0; i < 10; i++ {}    // Valid
+for (i = 0; i < 10; i++) {}  // INVALID
+
+ +

+Go does not have a while statement nor does it have a +do/while +statement. The for statement may be used with a single condition, +which makes it equivalent to a while statement. Omitting the +condition entirely is an endless loop. + +

+Go permits break and continue to specify a label. +The label must +refer to a for, switch, or select +statement. + +

+In a switch statement, case labels do not fall +through. You can +make them fall through using the fallthrough keyword. This applies +even to adjacent cases. + +

+switch i {
+case 0:  // empty case body
+case 1:
+    f()  // f is not called when i == 0!
+}
+
+ +

+But a case can have multiple values. + +

+switch i {
+case 0, 1:
+    f()  // f is called if i == 0 || i == 1.
+}
+
+ +

+The values in a case need not be constants—or even integers; +any type +that supports the equality comparison operator, such as strings or +pointers, can be used—and if the switch +value is omitted it defaults to true. + +

+switch {
+case i < 0:
+    f1()
+case i == 0:
+    f2()
+case i > 0:
+    f3()
+}
+
+ +

+The ++ and -- operators may only be used in +statements, not in expressions. +You cannot write c = *p++. *p++ is parsed as +(*p)++. + +

+The defer statement may be used to call a function after +the function containing the defer statement returns. + +

+fd := open("filename")
+defer close(fd)         // fd will be closed when this function returns.
+
+ +

Constants

+ +

+In Go constants may be untyped. This applies even to constants +named with a const declaration, if no +type is given in the declaration and the initializer expression uses only +untyped constants. +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
+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
+f(huge >> 98)
+
+ +

+Go does not support enums. Instead, you can use the special name +iota in a single const declaration to get a +series of increasing +value. When an initialization expression is omitted for a const, +it reuses the preceding expression. + +

+const (
+    red = iota   // red == 0
+    blue         // blue == 1
+    green        // green == 2
+)
+
+ +

Slices

+ +

+A slice is conceptually a struct with three fields: a +pointer to an array, a length, and a capacity. +Slices support +the [] operator to access elements of the underlying array. +The builtin +len function returns the +length of the slice. The builtin cap function returns the +capacity. + +

+Given an array, or another slice, a new slice is created via +a[I:J]. This +creates a new slice which refers to a, starts at +index I, and ends before index +J. It has length J - I. +The new slice refers to the same array +to which a +refers. That is, changes made using the new slice may be seen using +a. The +capacity of the new slice is simply the capacity of a 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; given var s []int; var a[10] int, +the assignment s = &a is equivalent to +s = a[0:len(a)]. + +

+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 +necessary to pass the length of the buffer; it is efficiently accessible via +len. + +

+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

+ +

+Go has a builtin function new which takes a type and +allocates space +on the heap. The allocated space will be zero-initialized for the type. +For example, new(int) allocates a new int on the heap, +initializes it with the value 0, +and returns its address, which has type *int. +Unlike in C++, new is a function, not an operator; +new int is a syntax error. + +

+Map and channel values must be allocated using the builtin function +make. +A variable declared with map or channel type without an initializer will be +automatically initialized to nil. +Calling make(map[int]int) returns a newly allocated value of +type map[int]int. +Note that make returns a value, not a pointer. This is +consistent with +the fact that map and channel values are passed by reference. Calling +make with +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. +In this case it +allocates memory for the underlying array and returns a slice referring to it. +There is one required argument, which is the number of elements in the slice. +A second, optional, argument is the capacity of the slice. For example, +make([]int, 10, 20). This is identical to +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

+ +

+Where C++ provides classes, subclasses and templates, +Go provides interfaces. A +Go interface is similar to a C++ pure abstract class: a class with no +data members, with methods which are all pure virtual. However, in +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 }
+
+ +

+This declares a method get associated with myType. +The receiver is named p 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 f(i int) { }
+var v myInteger
+// f(v) is invalid.
+// f(int(v)) is valid; int(v) has no defined methods.
+
+ +

+Given this interface: + +

+type myInterface interface {
+	get() int
+	set(i int)
+}
+
+ +

+we can make myType satisfy the interface by adding + +

+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 f1() {
+	var p myType
+	getAndSet(&p)
+}
+
+ +

+In other words, if we view myInterface as a C++ pure abstract +base +class, defining set and get for +*myType made *myType automatically +inherit from myInterface. 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() }
+
+ +

+This effectively implements myChildType as a child of +myType. + +

+func f2() {
+	var p myChildType
+	getAndSet(&p)
+}
+
+ +

+The set method is effectively inherited from +myChildType, because +methods associated with the anonymous field are promoted to become methods +of the enclosing type. In this case, because myChildType has an +anonymous field of type myType, the methods of +myType also become methods of myChildType. +In this example, the get method was +overridden, and the set method was inherited. + +

+This is not precisely the same as a child class in C++. +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 +different interface type using a special construct called a type assertion. +This is implemented dynamically +at run time, like C++ dynamic_cast. Unlike +dynamic_cast, there does +not need to be any declared relationship between the two interfaces. + +

+type myPrintInterface interface {
+  print()
+}
+func f3(x myInterface) {
+	x.(myPrintInterface).print()  // type assertion to myPrintInterface
+}
+
+ +

+The conversion to myPrintInterface is entirely dynamic. +It will +work as long as the underlying type of x (the dynamic type) defines +a print method. + +

+Because 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 { }
+
+ +

+Containers may be written in terms of Any, but the caller +must unbox using a type assertion to recover +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
+}
+
+ +

Goroutines

+ +

+Go permits starting a new thread of execution (a goroutine) +using the go +statement. The go 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)
+    }
+}
+go server(1)
+go server(2)
+
+ +

+(Note that the for statement in the server +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
+go func(i int) {
+	s := 0
+	for j := 0; j < i; j++ { s += j }
+	g = s
+}(1000)  // Passes argument 1000 to the function literal.
+
+ +

Channels

+ +

+Channels are used to communicate between goroutines. Any value may be +sent over a channel. Channels are (intended to be) efficient and +cheap. To send a value on a channel, use <- as a binary +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
+	for {
+		c := <- ch
+		if c.get { c.val = val; ch <- c }
+		else { val = c.val }
+	}
+}
+
+ +

+In that example the same channel is used for input and output. +This is incorrect if there are multiple goroutines communicating +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
+	for {
+		c := <- ch
+		if c.get { c.ch <- val }
+		else { val = c.val }
+	}
+}
+
+ +

+To use manager2, given a channel to it: + +

+func f4(ch <- chan cmd2) int {
+	myCh := make(chan int)
+	c := cmd2{ true, 0, myCh }   // Composite literal syntax.
+	ch <- c
+	return <-myCh
+}
+
-- cgit v1.2.3