From 2e5a136e458e6641b09fb3a0db72ce729a9f4f66 Mon Sep 17 00:00:00 2001
From: Rob Pike bufio.Reader
does not conflict with io.Reader.
+Similarly, the constructor for vector.Vector
+could be called NewVector but since
+Vector is the only type exported by the package, and since the
+package is called vector, it's called just New,
+which clients of the package see as vector.New.
Use the package structure to help you choose good names.
-In fact, semicolons can omitted at the end of any "StatementList" in the
+In fact, semicolons can be omitted at the end of any "StatementList" in the
grammar, which includes things like cases in switch
statements:
io.ReadFull that uses them well:
func ReadFull(r Reader, buf []byte) (n int, err os.Error) {
- for len(buf) > 0 && err != nil {
+ for len(buf) > 0 && err != nil {
var nr int;
nr, err = r.Read(buf);
n += nr;
@@ -721,38 +726,271 @@ func ReadFull(r Reader, buf []byte) (n int, err os.Error) {
}
+new()
+Go has two allocation primitives, new() and make().
+They do different things and apply to different types, which can be confusing,
+but the rules are simple.
+Let's talk about new() first.
+It's a built-in function essentially the same as its namesakes
+in other languages: it allocates zeroed storage for a new item of type
+T and returns its address, a value of type *T.
+In Go terminology, it returns a pointer to a newly allocated zero value of type
+T.
+
+Since the memory returned by new() is zeroed, it's helpful to arrange that the
+zeroed object can be used without further initialization. This means a user of
+the data structure can create one with new() and get right to
+work.
+For example, the documentation for bytes.Buffer states that
+"the zero value for Buffer is an empty buffer ready to use."
+Similarly, sync.Mutex does not
+have an explicit constructor or Init method.
+Instead, the zero value for a sync.Mutex
+is defined to be an unlocked mutex.
+
+The zero-value-is-useful property works transitively. Consider this type declaration: +
+ +
+type SyncedBuffer struct {
+ lock sync.Mutex;
+ buffer bytes.Buffer;
+}
+
+
+
+Values of type SyncedBuffer are also ready to use immediately upon allocation
+or just declaration. In this snippet, both p and v will work
+correctly without further arrangement:
+
+p := new(SyncedBuffer); // type *SyncedBuffer +var v SyncedBuffer; // type SyncedBuffer ++ +
+Sometimes the zero value isn't good enough and an initializing
+constructor is necessary, as in this example derived from
+package os:
+
+func NewFile(fd int, name string) *File {
+ if fd < 0 {
+ return nil
+ }
+ f := new(File);
+ f.fd = fd;
+ f.name = name;
+ f.error = nil;
+ f.dirinfo = nil;
+ f.nepipe = 0;
+ return f;
+}
+
+
++There's a lot of boilerplate in there. We can simplify it +using a composite literal, which is +an expression that creates a +new instance each time it is evaluated. +
+ + +
+func NewFile(fd int, name string) *File {
+ if file < 0 {
+ return nil
+ }
+ f := File{fd, name, nil, 0};
+ return &f;
+}
+
+
++Note that it's perfectly OK to return the address of a local variable; +the storage associated with the variable survives after the function +returns. +In fact, as a special case, the address of a composite literal +allocates a fresh instance each time, we can combine these last two lines: +
+ +
+ return &File{fd, name, nil, 0};
+
+
+
+The fields of a composite literal are laid out in order and must all be present.
+However, by labeling the elements explicitly as field:value
+pairs, the initializers can appear in any
+order, with the missing ones left as their respective zero values. Thus we could say
+
+ return &File{fd: fd, name: name}
+
+
++As a limiting case, if a composite literal contains no fields at all, it creates +a zero value for the type. These two expressions are equivalent: +
+ +
+new(File)
+&File{}
+
+
+
+Composite literals can also be created for arrays, slices, and maps,
+with the field labels being indices or map keys as appropriate.
+In these examples, the initializations work regardless of the values of EnoError,
+Eio, and Einval, as long as they are distinct:
+
+a := [...]string {Enone: "no error", Eio: "Eio", Einval: "invalid argument"};
+s := []string {Enone: "no error", Eio: "Eio", Einval: "invalid argument"};
+m := map[int]string{Enone: "no error", Eio: "Eio", Einval: "invalid argument"};
+
+
+make()
+Back to allocation.
+The built-in function make(T, args) serves
+a purpose different from new(T).
+It creates slices, maps, and channels only, and it returns an initialized (not zero)
+value of type T, not *T.
+The reason for the distinction
+is that these three types are, under the covers, references to data structures that
+must be initialized before use.
+A slice, for example, is a three-item descriptor
+containing a pointer to the data (inside an array), the length, and the
+capacity; until those items are initialized, the slice is nil.
+For slices, maps, and channels,
+make initializes the internal data structure and prepares
+the value for use.
+For instance,
+
+make([]int, 10, 100) ++ +
+allocates an array of 100 ints and then creates a slice
+structure with length 10 and a capacity of 100 pointing at the first
+10 elements of the array.
+(When making a slice, the capacity can be omitted; see the section on slices
+for more information.)
+In contrast, new([]int) returns a pointer to a newly allocated, zeroed slice
+structure, that is, a pointer to a nil slice value.
+
+
+These examples illustrate the difference between new() and
+make():
+
+var p *[]int = new([]int); // allocates slice structure; *p == nil; rarely useful +var v []int = make([]int, 100); // v now refers to a new array of 100 ints + +// Unnecessarily complex: +var p *[]int = new([]int); +*p = make([]int, 100, 100); + +// Idiomatic: +v := make([]int, 100); ++ +
+Remember that make() applies only to maps, slices and channels.
+To obtain an explicit pointer allocate with new().
+
+Arrays are useful when planning the detailed layout of memory and sometimes +can help avoid allocation but primarily +they are a building block for slices, the subject of the next section. +To lay the foundation for that topic, here are a few words about arrays. +
+ ++There are major differences between the ways arrays work in Go and C. +In Go: +
+[10]int
+and [20]int are distinct.
++The value property can be useful but also expensive; if you want C-like behavior and efficiency, +you can pass a pointer to the array: +
+ +
+func Sum(a *[]float) (sum float) {
+ for _, v := range a {
+ sum += v
+ }
+ return
+}
+
+array := [...]float{7.0, 8.5, 9.1};
+x := sum(&array); // Note the explicit address-of operator
+
+
++But even this style isn't idiomatic Go. Slices are. +
+ ++Slices wrap arrays to give a more general, powerful, and convenient interface to sequences +of data. +Except for items with explicit dimension such as rotation matrices, most +array programming in Go is done with slices rather than simple arrays. +
+ + +