From e2854875c559d23ab9124421c587f231787b6bc3 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Mon, 12 Oct 2009 15:43:13 -0700 Subject: [PATCH] Review and update. No major changes, lots of minor tweaks. R=go-dev DELTA=176 (39 added, 9 deleted, 128 changed) OCL=35612 CL=35623 --- doc/go_for_cpp_programmers.html | 228 ++++++++++++++++++-------------- 1 file changed, 129 insertions(+), 99 deletions(-) diff --git a/doc/go_for_cpp_programmers.html b/doc/go_for_cpp_programmers.html index d6d4329ba81..ccd7db56269 100644 --- a/doc/go_for_cpp_programmers.html +++ b/doc/go_for_cpp_programmers.html @@ -34,23 +34,25 @@ There is more documentation about go. use a pointer variable to walk through the bytes of a string.
  • Arrays in Go are first class values. When an array is used as a - function parameter, the function receives a copy of the array, - not a pointer to it. However, in practice functions often use - slices for parameters, rather than arrays. This is discussed further - below. + function parameter, the function receives a copy of the array, not + a pointer to it. However, in practice functions often use slices + for parameters; slices hold pointers to underlying arrays. Slices + are discussed further below. -
  • Strings are provided by the language. They may not change once they +
  • Strings are provided by the language. They may not be changed once they have been created.
  • Hash tables are provided by the language. They are called maps. -
  • Processes, and communication channels between them, are provided by - the language. This is discussed further below. +
  • Separate threads of execution, and communication channels between + them, are provided by the language. This + is discussed further below. -
  • Certain types (maps, channels, and slices, all described further below) +
  • Certain types (maps and channels, described further below) are passed by reference, not by value. That is, passing a map to a function does not copy the map, and if the function changes the map - the change will be seen by the caller. + the change will be seen by the caller. In C++ terms, one can + think of these as being reference types.
  • Go does not use header files. Instead, each source file is part of a defined package. When a package defines an object @@ -86,7 +88,7 @@ var v3 [10]int; // int v3[10]; var v4 []int; // approximately int* v4; var v5 struct { f int }; // struct { int f; } v5; var v6 *int; // int* v6; // but no pointer arithmetic -var v7 map[string]int; // approximately unordered_map<string, int>* v7; +var v7 map[string]int; // approximately unordered_map<string, int>* v7; var v8 func(a int) int; // int (*v8)(int a); @@ -97,7 +99,7 @@ of the object being declared. The keyword is one of var, const, or type. Method declarations are a minor exception in that the receiver appears before the name of the object begin declared; see -the discussion of interfaces. +the discussion of interfaces.

    You can also use a keyword followed by a series of declarations in @@ -108,7 +110,7 @@ var (i int; m float)

    -When declaring a function, you must provide a name for each parameter +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: @@ -174,24 +176,15 @@ always permitted at the end of a statement, so you can continue using them as in C++.

    -Go treats semicolons as separators, not terminators. Moreover, -a semicolon -is not required after a curly brace ending a type declaration (e.g., -var s struct {}) or a block. Semicolons are never required at the -top level of a file (between global declarations). However, they are -always permitted at -the end of a statement, so you can continue using them as in C++. - -

    -When using a pointer, you use . instead of ->. -Thus syntactically -speaking there is no difference between a structure and a pointer to a -structure. +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 my_struct struct { i int }
    -var v9 my_struct;             // v9 has structure type
    -var p9 *my_struct;            // p9 is a pointer to a structure
    +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)
     
    @@ -238,10 +231,10 @@ 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; +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 +pointers, can be used—and if the switch value is omitted it defaults to true.

    @@ -254,6 +247,15 @@ 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

    @@ -292,8 +294,11 @@ const ( red = iota; blue; green ) // red == 0, blue == 1, green == 2

    Slices

    -A slice is a pointer to an array, a length, and a capacity. Slices support -the [] operator to access elements. The builtin +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. @@ -383,82 +388,100 @@ 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. +has a receiver. The receiver is similar to +the this pointer in a C++ class method.

    -type my_type struct { i int }
    -func (p *my_type) get() int { return p.i }
    +type myType struct { i int }
    +func (p *myType) get() int { return p.i }
     

    -This declares a method get associated with my_type. +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 my_interface interface {
    -  get() int;
    -  set(i int);
    +type myInterface interface {
    +	get() int;
    +	set(i int);
     }
     

    -we can make my_type satisfy the interface by additionally writing +we can make myType satisfy the interface by additionally writing

    -func (p *my_type) set(i int) { p.i = i }
    +func (p *myType) set(i int) { p.i = i }
     

    -Now any function which takes my_interface as a parameter +Now any function which takes myInterface as a parameter will accept a -variable of type *my_type. +variable of type *myType.

    -func get_and_set(x my_interface);
    +func getAndSet(x myInterface);
     func f1() {
    -  var p my_type;
    -  get_and_set(&p);
    +	var p myType;
    +	getAndSet(&p);
     }
     

    -In other words, if we view my_interface as a C++ pure abstract +In other words, if we view myInterface as a C++ pure abstract base class, defining set and get for -*my_type made *my_type automatically -inherit from my_interface. A type may satisfy multiple interfaces. +*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 my_child_type struct { my_type; j int }
    -func (p *my_child_type) get() int { p.j++; return (&p.my_type).get() }
    +type myChildType struct { myType; j int }
    +func (p *myChildType) get() int { p.j++; return (&p.myType).get() }
     

    -This effectively implements my_child_type as a child of -my_type. +This effectively implements myChildType as a child of +myType.

     func f2() {
    -   var p my_child_type;
    -   get_and_set(&p)
    +	var p myChildType;
    +	getAndSet(&p)
     }
     

    The set method is effectively inherited from -my_child_type, because +myChildType, because methods associated with the anonymous type are promoted to become methods -of the enclosing type. In this case, because my_child_type has an -anonymous field of type my_type, the methods of -my_type also become methods of my_child_type. +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. @@ -478,23 +501,23 @@ at runtime, like C++ dynamic_cast. Unlike not need to be any declared relationship between the two interfaces.

    -type my_compare_interface interface {
    +type myCompareInterface interface {
       print();
     }
    -func f3(x my_interface) {
    -  x.(my_compare_interface).print()
    +func f3(x myInterface) {
    +	x.(myCompareInterface).print()
     }
     

    -The conversion to my_compare_interface is entirely dynamic. +The conversion to myCompareInterface is entirely dynamic. It will -work as long as the underlying type of x (the "dynamic type") defines +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, e.g., +programming similar to templates in C++. This is done by manipulating values of the minimal interface.

    @@ -510,19 +533,26 @@ at runtime, but all operations will involve a function call.
     
     
     type iterator interface {
    -  get() Any;
    -  set(v Any);
    -  increment();
    -  equal(arg *iterator) bool;
    +	get() Any;
    +	set(v Any);
    +	increment();
    +	equal(arg *iterator) bool;
     }
     
    -

    Processes

    +

    Goroutines

    -Go permits starting a new process (a "goroutine") using the go -statement. The go statement runs a function in a different process. -All processes in a single program share the same address space. +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) } }
    @@ -534,7 +564,7 @@ go server(1); go server(2);
     function is equivalent to a C++ while (true) loop).
     
     

    -Processes are (intended to be) cheap. +Goroutines are (intended to be) cheap.

    Function literals can be useful with the go statement. @@ -542,16 +572,16 @@ Function literals can be useful with the go statement.

     var g int // global variable
     go func(i int) {
    -  s := 0
    -  for j := 0; j < i; j++ { s += j }
    -  g = s
    +	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 processes. Any value may be +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 @@ -561,38 +591,38 @@ functions, channels are passed by reference.

    The Go library provides mutexes, but you can also use -a single process with a shared channel. +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 }
    -  }
    +	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 -means that if two processes try to retrieve the value at the same -time, the first process may read the response which was triggered by -the second process's request. In simple cases that is fine. For more +means that if two goroutines try to retrieve the value at the same +time, the first goroutine may read the response which was triggered by +the second goroutine's request. In simple cases that is fine. For more complex cases, 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 }
    -  }
    +	var val int = 0;
    +	for {
    +		c := <- ch
    +		if c.get { c.ch <- val }
    +		else { val = c.val }
    +	}
     }
     
    @@ -601,9 +631,9 @@ To use manager2, given a channel to it:
     func f4(ch <- chan cmd2) int {
    -  my_ch := make(chan int);
    -  c := cmd2 { true, 0, my_ch };  // Composite literal syntax.
    -  ch <- c;
    -  return <- my_ch;
    +	myCh := make(chan int);
    +	c := cmd2{ true, 0, myCh };  // Composite literal syntax.
    +	ch <- c;
    +	return <- myCh;
     }