]> Cypherpunks repositories - gostls13.git/commitdiff
tutorial: modernize the definition and use of Open.
authorRob Pike <r@golang.org>
Mon, 18 Apr 2011 17:51:40 +0000 (10:51 -0700)
committerRob Pike <r@golang.org>
Mon, 18 Apr 2011 17:51:40 +0000 (10:51 -0700)
R=golang-dev, iant
CC=golang-dev
https://golang.org/cl/4446053

doc/go_tutorial.html
doc/go_tutorial.txt
doc/progs/cat.go
doc/progs/cat_rot13.go
doc/progs/file.go
doc/progs/helloworld3.go

index e3d946f8d046c43acf640e34fb1f575dd83491f6..4d9c63e1587356775bf8d8c0e365308b2401dcf7 100644 (file)
@@ -474,8 +474,8 @@ assigned to a variable.
 <p>
 <h2>An I/O Package</h2>
 <p>
-Next we'll look at a simple package for doing file I/O with the usual
-sort of open/close/read/write interface.  Here's the start of <code>file.go</code>:
+Next we'll look at a simple package for doing file I/O with an
+open/close/read/write interface.  Here's the start of <code>file.go</code>:
 <p>
 <pre> <!-- progs/file.go /package/ /^}/ -->
 05    package file
@@ -554,10 +554,10 @@ We can use the factory to construct some familiar, exported variables of type <c
 </pre>
 <p>
 The <code>newFile</code> function was not exported because it's internal. The proper,
-exported factory to use is <code>Open</code>:
+exported factory to use is <code>OpenFile</code> (we'll explain that name in a moment):
 <p>
-<pre> <!-- progs/file.go /func.Open/ /^}/ -->
-30    func Open(name string, mode int, perm uint32) (file *File, err os.Error) {
+<pre> <!-- progs/file.go /func.OpenFile/ /^}/ -->
+30    func OpenFile(name string, mode int, perm uint32) (file *File, err os.Error) {
 31        r, e := syscall.Open(name, mode, perm)
 32        if e != 0 {
 33            err = os.Errno(e)
@@ -566,7 +566,7 @@ exported factory to use is <code>Open</code>:
 36    }
 </pre>
 <p>
-There are a number of new things in these few lines.  First, <code>Open</code> returns
+There are a number of new things in these few lines.  First, <code>OpenFile</code> returns
 multiple values, a <code>File</code> and an error (more about errors in a moment).
 We declare the
 multi-value return as a parenthesized list of declarations; syntactically
@@ -585,6 +585,35 @@ consistent error handling throughout Go code.   In <code>Open</code> we use a
 conversion to translate Unix's integer <code>errno</code> value into the integer type
 <code>os.Errno</code>, which implements <code>os.Error</code>.
 <p>
+Why <code>OpenFile</code> and not <code>Open</code>? To mimic Go's <code>os</code> package, which
+our exercise is emulating. The <code>os</code> package takes the opportunity
+to make the two commonest cases - open for read and create for
+write - the simplest, just <code>Open</code> and <code>Create</code>.  <code>OpenFile</code> is the
+general case, analogous to the Unix system call <code>Open</code>.  Here is
+the implementation of our <code>Open</code> and <code>Create</code>; they're trivial
+wrappers that eliminate common errors by capturing
+the tricky standard arguments to open and, especially, to create a file:
+<p>
+<pre> <!-- progs/file.go /^const/ /^}/ -->
+38    const (
+39        O_RDONLY = syscall.O_RDONLY
+40        O_RDWR   = syscall.O_RDWR
+41        O_CREATE = syscall.O_CREAT
+42        O_TRUNC  = syscall.O_TRUNC
+43    )
+<p>
+45    func Open(name string) (file *File, err os.Error) {
+46        return OpenFile(name, O_RDONLY, 0)
+47    }
+</pre>
+<p>
+<pre> <!-- progs/file.go /func.Create/ /^}/ -->
+49    func Create(name string) (file *File, err os.Error) {
+50        return OpenFile(name, O_RDWR|O_CREATE|O_TRUNC, 0666)
+51    }
+</pre>
+<p>
+Back to our main story.
 Now that we can build <code>Files</code>, we can write methods for them. To declare
 a method of a type, we define a function to have an explicit receiver
 of that type, placed
@@ -592,43 +621,43 @@ in parentheses before the function name. Here are some methods for <code>*File</
 each of which declares a receiver variable <code>file</code>.
 <p>
 <pre> <!-- progs/file.go /Close/ END -->
-38    func (file *File) Close() os.Error {
-39        if file == nil {
-40            return os.EINVAL
-41        }
-42        e := syscall.Close(file.fd)
-43        file.fd = -1 // so it can't be closed again
-44        if e != 0 {
-45            return os.Errno(e)
-46        }
-47        return nil
-48    }
-<p>
-50    func (file *File) Read(b []byte) (ret int, err os.Error) {
-51        if file == nil {
-52            return -1, os.EINVAL
-53        }
-54        r, e := syscall.Read(file.fd, b)
-55        if e != 0 {
-56            err = os.Errno(e)
-57        }
-58        return int(r), err
-59    }
-<p>
-61    func (file *File) Write(b []byte) (ret int, err os.Error) {
-62        if file == nil {
-63            return -1, os.EINVAL
-64        }
-65        r, e := syscall.Write(file.fd, b)
-66        if e != 0 {
-67            err = os.Errno(e)
+53    func (file *File) Close() os.Error {
+54        if file == nil {
+55            return os.EINVAL
+56        }
+57        e := syscall.Close(file.fd)
+58        file.fd = -1 // so it can't be closed again
+59        if e != 0 {
+60            return os.Errno(e)
+61        }
+62        return nil
+63    }
+<p>
+65    func (file *File) Read(b []byte) (ret int, err os.Error) {
+66        if file == nil {
+67            return -1, os.EINVAL
 68        }
-69        return int(r), err
-70    }
-<p>
-72    func (file *File) String() string {
-73        return file.name
+69        r, e := syscall.Read(file.fd, b)
+70        if e != 0 {
+71            err = os.Errno(e)
+72        }
+73        return int(r), err
 74    }
+<p>
+76    func (file *File) Write(b []byte) (ret int, err os.Error) {
+77        if file == nil {
+78            return -1, os.EINVAL
+79        }
+80        r, e := syscall.Write(file.fd, b)
+81        if e != 0 {
+82            err = os.Errno(e)
+83        }
+84        return int(r), err
+85    }
+<p>
+87    func (file *File) String() string {
+88        return file.name
+89    }
 </pre>
 <p>
 There is no implicit <code>this</code> and the receiver variable must be used to access
@@ -658,7 +687,7 @@ We can now use our new package:
 13    func main() {
 14        hello := []byte(&quot;hello, world\n&quot;)
 15        file.Stdout.Write(hello)
-16        f, err := file.Open(&quot;/does/not/exist&quot;,  0,  0)
+16        f, err := file.Open(&quot;/does/not/exist&quot;)
 17        if f == nil {
 18            fmt.Printf(&quot;can't open file; err=%s\n&quot;,  err.String())
 19            os.Exit(1)
@@ -723,7 +752,7 @@ Building on the <code>file</code> package, here's a simple version of the Unix u
 35            cat(file.Stdin)
 36        }
 37        for i := 0; i &lt; flag.NArg(); i++ {
-38            f, err := file.Open(flag.Arg(i), 0, 0)
+38            f, err := file.Open(flag.Arg(i))
 39            if f == nil {
 40                fmt.Fprintf(os.Stderr, &quot;cat: can't open %s: error %s\n&quot;, flag.Arg(i), err)
 41                os.Exit(1)
index 2b2a0cda1e62597543d9c966ef1bb67079ad2ce5..ab02baf2cd0ff371cb52051a47c2b7782f5684e4 100644 (file)
@@ -384,8 +384,8 @@ assigned to a variable.
 An I/O Package
 ----
 
-Next we'll look at a simple package for doing file I/O with the usual
-sort of open/close/read/write interface.  Here's the start of "file.go":
+Next we'll look at a simple package for doing file I/O with an
+open/close/read/write interface.  Here's the start of "file.go":
 
 --PROG progs/file.go /package/ /^}/
 
@@ -437,11 +437,11 @@ We can use the factory to construct some familiar, exported variables of type "*
 --PROG progs/file.go /var/ /^.$/
 
 The "newFile" function was not exported because it's internal. The proper,
-exported factory to use is "Open":
+exported factory to use is "OpenFile" (we'll explain that name in a moment):
 
---PROG progs/file.go /func.Open/ /^}/
+--PROG progs/file.go /func.OpenFile/ /^}/
 
-There are a number of new things in these few lines.  First, "Open" returns
+There are a number of new things in these few lines.  First, "OpenFile" returns
 multiple values, a "File" and an error (more about errors in a moment).
 We declare the
 multi-value return as a parenthesized list of declarations; syntactically
@@ -460,6 +460,20 @@ consistent error handling throughout Go code.   In "Open" we use a
 conversion to translate Unix's integer "errno" value into the integer type
 "os.Errno", which implements "os.Error".
 
+Why "OpenFile" and not "Open"? To mimic Go's "os" package, which
+our exercise is emulating. The "os" package takes the opportunity
+to make the two commonest cases - open for read and create for
+write - the simplest, just "Open" and "Create".  "OpenFile" is the
+general case, analogous to the Unix system call "Open".  Here is
+the implementation of our "Open" and "Create"; they're trivial
+wrappers that eliminate common errors by capturing
+the tricky standard arguments to open and, especially, to create a file:
+
+--PROG progs/file.go /^const/ /^}/
+
+--PROG progs/file.go /func.Create/ /^}/
+
+Back to our main story.
 Now that we can build "Files", we can write methods for them. To declare
 a method of a type, we define a function to have an explicit receiver
 of that type, placed
index 697e5f7865125870ff3cedafaffaaee619c79d19..9f0b8d4a3e23e4848b2d1eb730f6a311a5cc9dfc 100644 (file)
@@ -24,6 +24,7 @@ func cat(f *file.File) {
                case nr > 0:
                        if nw, ew := file.Stdout.Write(buf[0:nr]); nw != nr {
                                fmt.Fprintf(os.Stderr, "cat: error writing from %s: %s\n", f.String(), ew.String())
+                               os.Exit(1)
                        }
                }
        }
@@ -35,7 +36,7 @@ func main() {
                cat(file.Stdin)
        }
        for i := 0; i < flag.NArg(); i++ {
-               f, err := file.Open(flag.Arg(i), 0, 0)
+               f, err := file.Open(flag.Arg(i))
                if f == nil {
                        fmt.Fprintf(os.Stderr, "cat: can't open %s: error %s\n", flag.Arg(i), err)
                        os.Exit(1)
index 03fc02259a1dbb87397f201c5fbefb6fc2141f70..0eefe7cfc7e7ff4603d5633649acebb23cb2ba0f 100644 (file)
@@ -67,6 +67,7 @@ func cat(r reader) {
                        nw, ew := file.Stdout.Write(buf[0:nr])
                        if nw != nr {
                                fmt.Fprintf(os.Stderr, "cat: error writing from %s: %s\n", r.String(), ew.String())
+                               os.Exit(1)
                        }
                }
        }
@@ -78,7 +79,7 @@ func main() {
                cat(file.Stdin)
        }
        for i := 0; i < flag.NArg(); i++ {
-               f, err := file.Open(flag.Arg(i), 0, 0)
+               f, err := file.Open(flag.Arg(i))
                if f == nil {
                        fmt.Fprintf(os.Stderr, "cat: can't open %s: error %s\n", flag.Arg(i), err)
                        os.Exit(1)
index df3a3cf71c86f9f99e0d9d6d2ee1cfa7f4998102..2875ce73a6cf3988af901de59f2dbca6435052f9 100644 (file)
@@ -27,7 +27,7 @@ var (
        Stderr = newFile(syscall.Stderr, "/dev/stderr")
 )
 
-func Open(name string, mode int, perm uint32) (file *File, err os.Error) {
+func OpenFile(name string, mode int, perm uint32) (file *File, err os.Error) {
        r, e := syscall.Open(name, mode, perm)
        if e != 0 {
                err = os.Errno(e)
@@ -35,6 +35,21 @@ func Open(name string, mode int, perm uint32) (file *File, err os.Error) {
        return newFile(r, name), err
 }
 
+const (
+       O_RDONLY = syscall.O_RDONLY
+       O_RDWR   = syscall.O_RDWR
+       O_CREATE = syscall.O_CREAT
+       O_TRUNC  = syscall.O_TRUNC
+)
+
+func Open(name string) (file *File, err os.Error) {
+       return OpenFile(name, O_RDONLY, 0)
+}
+
+func Create(name string) (file *File, err os.Error) {
+       return OpenFile(name, O_RDWR|O_CREATE|O_TRUNC, 0666)
+}
+
 func (file *File) Close() os.Error {
        if file == nil {
                return os.EINVAL
index adbcea3247bbe7c798a93b39fc4cd9f8d44996b9..5bb0be2184f1a45a66bf009691e68d796c4f19ba 100644 (file)
@@ -13,7 +13,7 @@ import (
 func main() {
        hello := []byte("hello, world\n")
        file.Stdout.Write(hello)
-       f, err := file.Open("/does/not/exist",  0,  0)
+       f, err := file.Open("/does/not/exist")
        if f == nil {
                fmt.Printf("can't open file; err=%s\n",  err.String())
                os.Exit(1)