]> Cypherpunks repositories - gostls13.git/commitdiff
tutorial: describe unidirectional channels
authorRob Pike <r@golang.org>
Thu, 10 Nov 2011 22:02:14 +0000 (14:02 -0800)
committerRob Pike <r@golang.org>
Thu, 10 Nov 2011 22:02:14 +0000 (14:02 -0800)
R=golang-dev, adg, gri
CC=golang-dev
https://golang.org/cl/5370058

doc/go_tutorial.html
doc/go_tutorial.tmpl
doc/progs/server.go
doc/progs/server1.go

index 0127783a7465832aafef2980fd6cd98cc50bb9a9..9713c904159f26f46b2f81618339deb691c8fb72 100644 (file)
@@ -1377,7 +1377,7 @@ The <code>server</code> routine loops forever, receiving requests and, to avoid
 a long-running operation, starting a goroutine to do the actual work.
 <p>
 <pre><!--{{code "progs/server.go" `/func.server/` `/^}/`}}
--->func server(op binOp, service chan *request) {
+-->func server(op binOp, service &lt;-chan *request) {
     for {
         req := &lt;-service
         go run(op, req) // don&#39;t wait for it
@@ -1385,17 +1385,41 @@ a long-running operation, starting a goroutine to do the actual work.
 }
 </pre>
 <p>
-We construct a server in a familiar way, starting it and returning a channel
+There's a new feature in the signature of <code>server</code>: the type of the
+<code>service</code> channel specifies the direction of communication.
+A channel of plain <code>chan</code> type can be used both for sending and receiving.
+However, the type used when declaring a channel can be decorated with an arrow to
+indicate that the channel can be used only to send (<code>chan&lt;-</code>) or to
+receive (<code>&lt;-chan</code>) data.
+The arrow points towards or away from the <code>chan</code> to indicate whether data flows into or out of
+the channel.
+In the <code>server</code> function, <code>service &lt;-chan *request</code> is a "receive only" channel
+that the function can use only to <em>read</em> new requests.
+<p>
+We instantiate a server in a familiar way, starting it and returning a channel
 connected to it:
 <p>
 <pre><!--{{code "progs/server.go" `/func.startServer/` `/^}/`}}
--->func startServer(op binOp) chan *request {
+-->func startServer(op binOp) chan&lt;- *request {
     req := make(chan *request)
     go server(op, req)
     return req
 }
 </pre>
 <p>
+The returned channel is send only, even though the channel was created bidirectionally.
+The read end is passed to <code>server</code>, while the send end is returned
+to the caller of <code>startServer</code>, so the two halves of the channel
+are distinguished, just as we did in <code>startServer</code>.
+<p>
+Bidirectional channels can be assigned to unidirectional channels but not the
+other way around, so if you annotate your channel directions when you declare
+them, such as in function signatures, the type system can help you set up and
+use channels correctly.
+Note that it's pointless to <code>make</code> unidirectional channels, since you can't
+use them to communicate. Their purpose is served by variables assigned from bidirectional channels
+to distinguish the input and output halves.
+<p>
 Here's a simple test.  It starts a server with an addition operator and sends out
 <code>N</code> requests without waiting for the replies.  Only after all the requests are sent
 does it check the results.
@@ -1437,7 +1461,7 @@ we can provide a second, <code>quit</code> channel to the server:
 It passes the quit channel to the <code>server</code> function, which uses it like this:
 <p>
 <pre><!--{{code "progs/server1.go" `/func.server/` `/^}/`}}
--->func server(op binOp, service chan *request, quit chan bool) {
+-->func server(op binOp, service &lt;-chan *request, quit &lt;-chan bool) {
     for {
         select {
         case req := &lt;-service:
index 21496ddd980d52ea9a2adefcbd22988e6166af37..dfd818959c45b3b5de356cf32e188aed871a14e4 100644 (file)
@@ -968,11 +968,35 @@ a long-running operation, starting a goroutine to do the actual work.
 <p>
 {{code "progs/server.go" `/func.server/` `/^}/`}}
 <p>
-We construct a server in a familiar way, starting it and returning a channel
+There's a new feature in the signature of <code>server</code>: the type of the
+<code>service</code> channel specifies the direction of communication.
+A channel of plain <code>chan</code> type can be used both for sending and receiving.
+However, the type used when declaring a channel can be decorated with an arrow to
+indicate that the channel can be used only to send (<code>chan&lt;-</code>) or to
+receive (<code>&lt;-chan</code>) data.
+The arrow points towards or away from the <code>chan</code> to indicate whether data flows into or out of
+the channel.
+In the <code>server</code> function, <code>service &lt;-chan *request</code> is a "receive only" channel
+that the function can use only to <em>read</em> new requests.
+<p>
+We instantiate a server in a familiar way, starting it and returning a channel
 connected to it:
 <p>
 {{code "progs/server.go" `/func.startServer/` `/^}/`}}
 <p>
+The returned channel is send only, even though the channel was created bidirectionally.
+The read end is passed to <code>server</code>, while the send end is returned
+to the caller of <code>startServer</code>, so the two halves of the channel
+are distinguished, just as we did in <code>startServer</code>.
+<p>
+Bidirectional channels can be assigned to unidirectional channels but not the
+other way around, so if you annotate your channel directions when you declare
+them, such as in function signatures, the type system can help you set up and
+use channels correctly.
+Note that it's pointless to <code>make</code> unidirectional channels, since you can't
+use them to communicate. Their purpose is served by variables assigned from bidirectional channels
+to distinguish the input and output halves.
+<p>
 Here's a simple test.  It starts a server with an addition operator and sends out
 <code>N</code> requests without waiting for the replies.  Only after all the requests are sent
 does it check the results.
index b498b53a63c8bc034ba0214725898a267c23393b..4d8409b801e8543fd6bae56ec2e4d1a3ee3e0691 100644 (file)
@@ -18,14 +18,14 @@ func run(op binOp, req *request) {
        req.replyc <- reply
 }
 
-func server(op binOp, service chan *request) {
+func server(op binOp, service <-chan *request) {
        for {
                req := <-service
                go run(op, req) // don't wait for it
        }
 }
 
-func startServer(op binOp) chan *request {
+func startServer(op binOp) chan<- *request {
        req := make(chan *request)
        go server(op, req)
        return req
index a4093924b8ec21e8f47eb35a1c5743a2dce4bad0..39e3dde5da7690841daaa5768aace61e8c5769f0 100644 (file)
@@ -18,7 +18,7 @@ func run(op binOp, req *request) {
        req.replyc <- reply
 }
 
-func server(op binOp, service chan *request, quit chan bool) {
+func server(op binOp, service <-chan *request, quit <-chan bool) {
        for {
                select {
                case req := <-service: