Compare commits
19 Commits
dev.power6
...
release.r5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
16b4a007de | ||
|
|
0bd41f1e48 | ||
|
|
ca2cb382ba | ||
|
|
658a82a13b | ||
|
|
9f89972666 | ||
|
|
125e91a174 | ||
|
|
3854d346f6 | ||
|
|
348ffe7786 | ||
|
|
69e88b5c52 | ||
|
|
006e5e279b | ||
|
|
5af3c75e30 | ||
|
|
a7ae73d4e0 | ||
|
|
6a9e2c7279 | ||
|
|
50e57603ab | ||
|
|
d00421a6b1 | ||
|
|
b69a320781 | ||
|
|
ed54b19716 | ||
|
|
29fdaadbef | ||
|
|
5ce9a8d4fc |
47
.hgignore
@@ -2,13 +2,13 @@ syntax:glob
|
||||
.DS_Store
|
||||
.git
|
||||
.gitignore
|
||||
*.[5689ao]
|
||||
*.a[5689o]
|
||||
*.[568ao]
|
||||
*.ao
|
||||
*.so
|
||||
*.pyc
|
||||
._*
|
||||
.nfs.*
|
||||
[5689a].out
|
||||
[568a].out
|
||||
*~
|
||||
*.orig
|
||||
*.rej
|
||||
@@ -23,33 +23,40 @@ _test
|
||||
_testmain.go
|
||||
build.out
|
||||
test.out
|
||||
doc/articles/wiki/*.bin
|
||||
include/plan9/libc_plan9.h
|
||||
y.tab.[ch]
|
||||
doc/htmlgen
|
||||
doc/codelab/wiki/*.bin
|
||||
misc/cgo/life/run.out
|
||||
misc/cgo/stdio/run.out
|
||||
misc/cgo/testso/main
|
||||
misc/dashboard/builder/builder
|
||||
src/cmd/?a/y.output
|
||||
src/liblink/anames?.c
|
||||
misc/dashboard/builder/gobuilder
|
||||
misc/goplay/goplay
|
||||
src/Make.inc
|
||||
src/cmd/6a/6a
|
||||
src/cmd/?l/enam.c
|
||||
src/cmd/cc/y.output
|
||||
src/cmd/cgo/zdefaultcc.go
|
||||
src/cmd/dist/dist.dSYM
|
||||
src/cmd/gc/builtin.c
|
||||
src/cmd/gc/mkbuiltin1
|
||||
src/cmd/gc/opnames.h
|
||||
src/cmd/gc/y.output
|
||||
src/cmd/go/zdefaultcc.go
|
||||
src/go/doc/headscan
|
||||
src/runtime/mkversion
|
||||
src/runtime/z*
|
||||
src/unicode/maketables
|
||||
src/*.*/
|
||||
src/cmd/gc/y1.tab.c
|
||||
src/cmd/gc/yerr.h
|
||||
src/cmd/goinstall/syslist.go
|
||||
src/pkg/Make.deps
|
||||
src/pkg/exp/ogle/ogle
|
||||
src/pkg/os/signal/unix.go
|
||||
src/pkg/runtime/*/asm.h
|
||||
src/pkg/runtime/goc2c
|
||||
src/pkg/runtime/mkversion
|
||||
src/pkg/runtime/runtime.acid.*
|
||||
src/pkg/runtime/runtime_defs.go
|
||||
src/pkg/runtime/version.go
|
||||
src/pkg/runtime/version_*.go
|
||||
src/pkg/unicode/maketables
|
||||
src/pkg/*.*/
|
||||
test/pass.out
|
||||
test/run.out
|
||||
test/times.out
|
||||
test/garbage/*.out
|
||||
goinstall.log
|
||||
last-change
|
||||
VERSION.cache
|
||||
|
||||
syntax:regexp
|
||||
^bin/
|
||||
|
||||
78
.hgtags
@@ -55,84 +55,8 @@ b2be017f91348d5f8cbaf42f77a99fc905044b59 weekly.2011-02-15
|
||||
21848430d60167817ca965c813a2118068ca660f weekly.2011-03-07
|
||||
c5c62aeb6267e124cf05f9622e28dbd0dc6b971d weekly.2011-03-07.1
|
||||
c5c62aeb6267e124cf05f9622e28dbd0dc6b971d release.r56
|
||||
c5c62aeb6267e124cf05f9622e28dbd0dc6b971d release
|
||||
3b4e9c85b643a35860805718323b05186dd7f235 weekly.2011-03-15
|
||||
b84e614e25161f626a6102813c41a80a15e3a625 weekly.2011-03-28
|
||||
cd89452cfea3d125aaf75a1ec8004e2f6a868d38 weekly.2011-04-04
|
||||
d6903b7fbff40c13ee7ea3177c0ae54c7f89d2e6 weekly.2011-04-13
|
||||
2f0fa51fa2da6ab50fcebba526326153da8ed999 weekly.2011-04-27
|
||||
8493bb64e5592bd20c0e60e78e7f8052c1276fcf release.r57
|
||||
95d2ce135523c96c4cea049af94ce76dd8c7d981 release.r57.1
|
||||
c98449d685d2b6aa1df9bfd2e1cce9307efb6e00 weekly.2011-05-22
|
||||
3418f22c39eb8299053ae681199ee90f8cd29c6d weekly.2011-06-02
|
||||
c81944152e973a917797679055b8fcdc70fbc802 weekly.2011-06-09
|
||||
9d7967223815ef6415ff01aa0fe6ad38cdbc7810 release.r57.2
|
||||
dac76f0b1a18a5de5b54a1dc0b231aceaf1c8583 weekly.2011-06-16
|
||||
541c445d6c1353fbfa39df7dc4b0eb27558d1fc1 weekly.2011-06-23
|
||||
1b38d90eebcddefabb3901c5bb63c7e2b04a6ec5 release.r58
|
||||
16bfa562ba767aefd82e598da8b15ee4729e23b0 weekly.2011-07-07
|
||||
d292bc7886682d35bb391bf572be28656baee12d release.r58.1
|
||||
3c21f37b25a3f7a1726265c5339c8a7b0b329336 weekly.2011-07-19
|
||||
bb28251f6da4aca85658582c370c7df89d34efd4 weekly.2011-07-29
|
||||
d5785050f61d973fc36775f7bd2e26689529cb3e release.r59
|
||||
c17ce5ec06b4bd5cf6e7ff2ceb0a60c2e40e0b17 weekly.2011-08-10
|
||||
6eb2b9dbe489acb57a2bfc1de31ec2239ed94326 weekly.2011-08-17
|
||||
c934f6f5fe8b30b4b3210ee3f13669e6e4670c32 weekly.2011-09-01
|
||||
c77997547d546c36c7b969586a36de7ceda74e33 weekly.2011-09-07
|
||||
b0819469a6df6029a27192fe7b19a73d97404c63 release.r60
|
||||
8a09ce0cefc64deab4e6d1ed59a08a53e879bbee weekly.2011-09-16
|
||||
fd30c132d1bdeb79f8f111cb721fb1c78b767b27 release.r60.1
|
||||
d7322ae4d055a4cf3efaf842d0717a41acd85bac weekly.2011-09-21
|
||||
32a5db19629897641b2d488de4d1b998942ef80e release.r60.2
|
||||
3bdabf483805fbf0c7ef013fd09bfd6062b9d3f2 weekly.2011-10-06
|
||||
c1702f36df0397c19fc333571a771666029aa37e release.r60.3
|
||||
acaddf1cea75c059d19b20dbef35b20fb3f38954 release.r58.2
|
||||
6d7136d74b656ba6e1194853a9486375005227ef weekly.2011-10-18
|
||||
941b8015061a0f6480954821dd589c60dfe35ed1 weekly.2011-10-25
|
||||
7c1f789e6efd153951e85e3f28722fc69efc2af2 weekly.2011-10-26
|
||||
e69e528f2afc25a8334cfb9359fa4fcdf2a934b6 weekly.2011-11-01
|
||||
780c85032b174c9d4b42adf75d82bc85af7d78d1 weekly.2011-11-02
|
||||
f4397ad6e87c7ce5feac9b01686f1ebd6cbaac4e weekly.2011-11-08
|
||||
2f4482b89a6b5956828872137b6b96636cd904d3 weekly.2011-11-09
|
||||
b4a91b6933748db1a7150c06a1b55ad506e52906 weekly.2011-11-18
|
||||
80db2da6495a20ddff8305c236825811db8c8665 weekly.2011-12-01
|
||||
0beb796b4ef8747af601ed5ea6766d5b1340086b weekly.2011-12-02
|
||||
0c39eee85b0d1606b79c8ebcdeb3b67ed5849e39 weekly.2011-12-06
|
||||
82fdc445f2ff2c85043446eb84a19cc999dfcb95 weekly.2011-12-14
|
||||
4a82689277582a2a60f006e3f158985f2f8d1da3 weekly.2011-12-22
|
||||
354b17404643c0f1a710bdc48927dff02f203ae3 weekly.2012-01-15
|
||||
9f2be4fbbf690b9562c6e98b91daa0003f0913c7 weekly.2012-01-20
|
||||
1107a7d3cb075836387adfab5ce56d1b3e56637d weekly.2012-01-27
|
||||
52ba9506bd993663a0a033c2bd68699e25d061ab weekly.2012-02-07
|
||||
43cf9b39b6477d3144b0353ee91096e55db6107f weekly.2012-02-14
|
||||
96bd78e7d35e892113bdfa1bdc392d3a5f2e644b weekly.2012-02-22
|
||||
f4470a54e6dbcdd52d8d404e12e4754adcd2c948 weekly.2012-03-04
|
||||
3cdba7b0650c6c906ef3e782654f61701abd7dd2 weekly.2012-03-13
|
||||
bce220d0377405146527ab9478867cbc572a6886 weekly.2012-03-22
|
||||
dc5e410f0b4c32ab11dc992593a2bcf5f607381b weekly.2012-03-27
|
||||
dc5e410f0b4c32ab11dc992593a2bcf5f607381b weekly
|
||||
920e9d1ffd1f46665dd152aa9cf3c0f17d68dd88 go1
|
||||
2ccfd4b451d319941bfe3e08037e1462d3c15093 go1.0.1
|
||||
5e806355a9e1491aaab53d3612fed4c550b130c0 go1.0.2
|
||||
2d8bc3c94ecb3ec8f70556d5fd237788903c7281 go1.0.3
|
||||
35da6063e57f8cefc82ba1ea542c4d9393ea9dfd go1.1rc2
|
||||
5a15f0dae37931da46f0356cf4cffe775a061c12 go1.1rc3
|
||||
e570c2daeaca10663d36d6dee7f8d1d76e8f7b92 go1.1
|
||||
a7bd9a33067b3537351276e0178a045748ad046a go1.1.1
|
||||
414057ac1f1fc850957088e4c5e95cdbccd2d594 go1.1.2
|
||||
45475ec7eab1c588fc4210b34d5901b15ca1e479 go1.2rc2
|
||||
7422495a6bf9d5e84828ee466406293be84f565a go1.2rc3
|
||||
94af58f9fd71feda5c316d791ed11aaf015f9e82 go1.2rc4
|
||||
b3d5a20b070a92da2458c5788694d1359b353f4a go1.2rc5
|
||||
87dea3f5ebe7510998c84dbeeec89382b7d42f9c go1.2
|
||||
0ddbdc3c7ce27e66508fe58ab81ff29324786026 go1.2.1
|
||||
9c4fdd8369ca4483fbed1cb8e67f02643ca10f79 go1.2.2
|
||||
f8b50ad4cac4d4c4ecf48324b4f512f65e82cc1c go1.3beta1
|
||||
9e1652c32289c164126b6171f024afad5665fc9e go1.3beta2
|
||||
9d5451df4e53acc58a848005b7ec3a24c4b6050c go1.3rc1
|
||||
3f66a43d5180052e2e1e38d979d1aa5ad05b21f9 go1.3rc2
|
||||
9895f9e36435468d503eaa74ee217f28d5e28dd4 go1.3
|
||||
073fc578434bf3e1e22749b559d273c8da728ebb go1.3.1
|
||||
85518b1d6f8d6e16133b9ed2c9db6807522d37de go1.3.2
|
||||
f44017549ff9c3cc5eef74ebe7276cd0dfc066b6 go1.3.3
|
||||
f44017549ff9c3cc5eef74ebe7276cd0dfc066b6 release
|
||||
1fdfd7dfaedb1b7702141617e621ab7328a236a1 go1.4beta1
|
||||
|
||||
323
AUTHORS
@@ -8,451 +8,134 @@
|
||||
|
||||
# Please keep the list sorted.
|
||||
|
||||
Aaron France <aaron.l.france@gmail.com>
|
||||
Abhinav Gupta <abhinav.g90@gmail.com>
|
||||
Adrian Nos <nos.adrian@gmail.com>
|
||||
Adrian O'Grady <elpollouk@gmail.com>
|
||||
Adrien Bustany <adrien-xx-google@bustany.org>
|
||||
Ahmed Waheed Moanes <oneofone@gmail.com>
|
||||
Akshat Kumar <seed@mail.nanosouffle.net>
|
||||
Alan Shreve <alan@inconshreveable.com>
|
||||
Albert Strasheim <fullung@gmail.com>
|
||||
Alberto Donizetti <alb.donizetti@gmail.com>
|
||||
Alberto García Hierro <alberto@garciahierro.com> <alberto.garcia.hierro@gmail.com>
|
||||
Aleksandar Dezelin <dezelin@gmail.com>
|
||||
Alex A Skinner <alex@lx.lc>
|
||||
Alex Brainman <alex.brainman@gmail.com>
|
||||
Alex Jin <toalexjin@gmail.com>
|
||||
Alexander Larsson <alexander.larsson@gmail.com>
|
||||
Alexander Orlov <alexander.orlov@loxal.net>
|
||||
Alexander Reece <awreece@gmail.com>
|
||||
Alexander Surma <surma@surmair.de>
|
||||
Alexander Zhavnerchik <alex.vizor@gmail.com>
|
||||
Alexandre Normand <alexandre.normand@gmail.com>
|
||||
Alexei Sholik <alcosholik@gmail.com>
|
||||
Alexey Borzenkov <snaury@gmail.com>
|
||||
Alexey Palazhchenko <alexey.palazhchenko@gmail.com>
|
||||
Amir Mohammad Saied <amir@gluegadget.com>
|
||||
Amrut Joshi <amrut.joshi@gmail.com>
|
||||
Andrei Vieru <euvieru@gmail.com>
|
||||
Andrew Balholm <andybalholm@gmail.com>
|
||||
Andrew Bonventre <andybons@chromium.org>
|
||||
Andrew Bursavich <abursavich@gmail.com>
|
||||
Andrew Harding <andrew@spacemonkey.com>
|
||||
Andrew Lutomirski <andy@luto.us>
|
||||
Andrew Pritchard <awpritchard@gmail.com>
|
||||
Andrew Radev <andrey.radev@gmail.com>
|
||||
Andrew Skiba <skibaa@gmail.com>
|
||||
Andrew Szeto <andrew@jabagawee.com>
|
||||
Andrew Wilkins <axwalk@gmail.com>
|
||||
Andrey Mirtchovski <mirtchovski@gmail.com>
|
||||
Andriy Lytvynov <lytvynov.a.v@gmail.com>
|
||||
Andy Davis <andy@bigandian.com>
|
||||
Anfernee Yongkun Gui <anfernee.gui@gmail.com>
|
||||
Anh Hai Trinh <anh.hai.trinh@gmail.com>
|
||||
Anschel Schaffer-Cohen <anschelsc@gmail.com>
|
||||
Anthony Eufemio <anthony.eufemio@gmail.com>
|
||||
Anthony Martin <ality@pbrane.org>
|
||||
Anthony Starks <ajstarks@gmail.com>
|
||||
Apisak Darakananda <pongad@gmail.com>
|
||||
Aram Hăvărneanu <aram@mgk.ro>
|
||||
Arnaud Ysmal <arnaud.ysmal@gmail.com>
|
||||
Arne Hormann <arnehormann@gmail.com>
|
||||
Aron Nopanen <aron.nopanen@gmail.com>
|
||||
Arvindh Rajesh Tamilmani <art@a-30.net>
|
||||
Ato Araki <ato.araki@gmail.com>
|
||||
Aulus Egnatius Varialus <varialus@gmail.com>
|
||||
Ben Olive <sionide21@gmail.com>
|
||||
Benjamin Black <b@b3k.us>
|
||||
Benny Siegert <bsiegert@gmail.com>
|
||||
Benoit Sigoure <tsunanet@gmail.com>
|
||||
Berengar Lehr <berengar.lehr@gmx.de>
|
||||
Billie Harold Cleek <bhcleek@gmail.com>
|
||||
Bjorn Tillenius <bjorn@tillenius.me>
|
||||
Bjorn Tipling <bjorn.tipling@gmail.com>
|
||||
Blake Mizerany <blake.mizerany@gmail.com>
|
||||
Bobby Powers <bobbypowers@gmail.com>
|
||||
Brendan Daniel Tracey <tracey.brendan@gmail.com>
|
||||
Brian Dellisanti <briandellisanti@gmail.com>
|
||||
Brian G. Merrell <bgmerrell@gmail.com>
|
||||
Brian Gitonga Marete <marete@toshnix.com>
|
||||
Brian Ketelsen <bketelsen@gmail.com>
|
||||
Caine Tighe <arctanofyourface@gmail.com>
|
||||
Caleb Spare <cespare@gmail.com>
|
||||
Carl Chatfield <carlchatfield@gmail.com>
|
||||
Carlos Castillo <cookieo9@gmail.com>
|
||||
Case Nelson <case.nelson@gmail.com>
|
||||
Casey Marshall <casey.marshall@gmail.com>
|
||||
Cezar Sá Espinola <cezarsa@gmail.com>
|
||||
ChaiShushan <chaishushan@gmail.com>
|
||||
Charles L. Dorian <cldorian@gmail.com>
|
||||
Charles Lee <zombie.fml@gmail.com>
|
||||
Chris Dollin <ehog.hedge@gmail.com>
|
||||
Chris Farmiloe <chrisfarms@gmail.com>
|
||||
Chris Howey <howeyc@gmail.com>
|
||||
Chris Jones <chris@cjones.org>
|
||||
Chris Lennert <calennert@gmail.com>
|
||||
Chris McGee <sirnewton_01@yahoo.ca> <newton688@gmail.com>
|
||||
Christian Himpel <chressie@googlemail.com>
|
||||
Christine Hansmann <chhansmann@gmail.com>
|
||||
Christoffer Buchholz <christoffer.buchholz@gmail.com>
|
||||
Christoph Hack <christoph@tux21b.org>
|
||||
Christopher Cahoon <chris.cahoon@gmail.com>
|
||||
Christopher Nielsen <m4dh4tt3r@gmail.com>
|
||||
Christopher Redden <christopher.redden@gmail.com>
|
||||
Christopher Wedgwood <cw@f00f.org>
|
||||
Clement Skau <clementskau@gmail.com>
|
||||
Conrad Meyer <cemeyer@cs.washington.edu>
|
||||
Corey Thomasson <cthom.lists@gmail.com>
|
||||
Cristian Staretu <unclejacksons@gmail.com>
|
||||
Damian Gryski <dgryski@gmail.com>
|
||||
Dan Callahan <dan.callahan@gmail.com>
|
||||
Dan Peterson <dpiddy@gmail.com>
|
||||
Dan Sinclair <dan.sinclair@gmail.com>
|
||||
Daniel Fleischman <danielfleischman@gmail.com>
|
||||
Daniel Krech <eikeon@eikeon.com>
|
||||
Daniel Lidén <daniel.liden.87@gmail.com>
|
||||
Daniel Morsing <daniel.morsing@gmail.com>
|
||||
Daniel Theophanes <kardianos@gmail.com>
|
||||
Darren Elwood <darren@textnode.com>
|
||||
Dave Cheney <dave@cheney.net>
|
||||
David Bürgin <676c7473@gmail.com>
|
||||
David Calavera <david.calavera@gmail.com>
|
||||
David du Colombier <0intro@gmail.com>
|
||||
David Forsythe <dforsythe@gmail.com>
|
||||
David G. Andersen <dave.andersen@gmail.com>
|
||||
David Jakob Fritz <david.jakob.fritz@gmail.com>
|
||||
David Leon Gil <coruus@gmail.com>
|
||||
David Thomas <davidthomas426@gmail.com>
|
||||
David Titarenco <david.titarenco@gmail.com>
|
||||
Dean Prichard <dean.prichard@gmail.com>
|
||||
Denis Brandolini <denis.brandolini@gmail.com>
|
||||
Derek Parker <parkerderek86@gmail.com>
|
||||
Devon H. O'Dell <devon.odell@gmail.com>
|
||||
Dhiru Kholia <dhiru.kholia@gmail.com>
|
||||
Dimitri Tcaciuc <dtcaciuc@gmail.com>
|
||||
Dmitri Shuralyov <shurcooL@gmail.com>
|
||||
Dmitriy Shelenin <deemok@googlemail.com> <deemok@gmail.com>
|
||||
Dmitry Chestnykh <dchest@gmail.com>
|
||||
Dominik Honnef <dominik.honnef@gmail.com>
|
||||
Donovan Hide <donovanhide@gmail.com>
|
||||
Dropbox, Inc.
|
||||
Duncan Holm <mail@frou.org>
|
||||
Dustin Sallings <dsallings@gmail.com>
|
||||
Dustin Shields-Cloues <dcloues@gmail.com>
|
||||
Eden Li <eden.li@gmail.com>
|
||||
Egon Elbre <egonelbre@gmail.com>
|
||||
Ehren Kret <ehren.kret@gmail.com>
|
||||
Eivind Uggedal <eivind@uggedal.com>
|
||||
Elias Naur <elias.naur@gmail.com>
|
||||
Emil Hessman <c.emil.hessman@gmail.com>
|
||||
Eoghan Sherry <ejsherry@gmail.com>
|
||||
Eric Clark <zerohp@gmail.com>
|
||||
Eric Milliken <emilliken@gmail.com>
|
||||
Eric Roshan-Eisner <eric.d.eisner@gmail.com>
|
||||
Erik St. Martin <alakriti@gmail.com>
|
||||
Erik Westrup <erik.westrup@gmail.com>
|
||||
Esko Luontola <esko.luontola@gmail.com>
|
||||
Eric Eisner <eric.d.eisner@gmail.com>
|
||||
Evan Shaw <chickencha@gmail.com>
|
||||
Ewan Chou <coocood@gmail.com>
|
||||
Fabrizio Milo <mistobaan@gmail.com>
|
||||
Fan Hongjian <fan.howard@gmail.com>
|
||||
Fastly, Inc.
|
||||
Fatih Arslan <fatih@arslan.io>
|
||||
Fazlul Shahriar <fshahriar@gmail.com>
|
||||
Felix Geisendörfer <haimuiba@gmail.com>
|
||||
Firmansyah Adiputra <frm.adiputra@gmail.com>
|
||||
Florian Uekermann <florian@uekermann-online.de>
|
||||
Florian Weimer <fw@deneb.enyo.de>
|
||||
Francisco Souza <franciscossouza@gmail.com>
|
||||
Frederick Kelly Mayle III <frederickmayle@gmail.com>
|
||||
Fredrik Enestad <fredrik.enestad@soundtrackyourbrand.com>
|
||||
Frithjof Schulze <schulze@math.uni-hannover.de> <sfrithjof@gmail.com>
|
||||
Gabriel Aszalos <gabriel.aszalos@gmail.com>
|
||||
Gary Burd <gary@beagledreams.com>
|
||||
Gautham Thambidorai <gautham.dorai@gmail.com>
|
||||
Georg Reinke <guelfey@gmail.com>
|
||||
Gerasimos Dimitriadis <gedimitr@gmail.com>
|
||||
Gideon Jan-Wessel Redelinghuys <gjredelinghuys@gmail.com>
|
||||
Giles Lean <giles.lean@pobox.com>
|
||||
Google Inc.
|
||||
Gordon Klaus <gordon.klaus@gmail.com>
|
||||
Graham King <graham4king@gmail.com>
|
||||
Graham Miller <graham.miller@gmail.com>
|
||||
Greg Ward <greg@gerg.ca>
|
||||
Guillaume J. Charmes <guillaume@charmes.net>
|
||||
Gustav Paul <gustav.paul@gmail.com>
|
||||
Gustavo Niemeyer <gustavo@niemeyer.net>
|
||||
Gwenael Treguier <gwenn.kahz@gmail.com>
|
||||
Harley Laue <losinggeneration@gmail.com>
|
||||
Hector Chu <hectorchu@gmail.com>
|
||||
Hector Martin Cantero <hector@marcansoft.com>
|
||||
Henning Schmiedehausen <henning@schmiedehausen.org>
|
||||
Henrik Edwards <henrik.edwards@gmail.com>
|
||||
Herbert Georg Fischer <herbert.fischer@gmail.com>
|
||||
Hong Ruiqi <hongruiqi@gmail.com>
|
||||
Icarus Sparry <golang@icarus.freeuk.com>
|
||||
Ingo Oeser <nightlyone@googlemail.com>
|
||||
Isaac Wagner <ibw@isaacwagner.me>
|
||||
Jakob Borg <jakob@nym.se>
|
||||
Jakub Ryszard Czarnowicz <j.czarnowicz@gmail.com>
|
||||
James David Chalfant <james.chalfant@gmail.com>
|
||||
James Fysh <james.fysh@gmail.com>
|
||||
James Gray <james@james4k.com>
|
||||
James Meneghello <rawrz0r@gmail.com>
|
||||
James P. Cooper <jamespcooper@gmail.com>
|
||||
James Toy <nil@opensesame.st>
|
||||
James Whitehead <jnwhiteh@gmail.com>
|
||||
Jan H. Hosang <jan.hosang@gmail.com>
|
||||
Jan Mercl <0xjnml@gmail.com>
|
||||
Jan Mercl <befelemepeseveze@gmail.com>
|
||||
Jan Newmarch <jan.newmarch@gmail.com>
|
||||
Jan Ziak <0xe2.0x9a.0x9b@gmail.com>
|
||||
Jani Monoses <jani.monoses@ubuntu.com>
|
||||
Jaroslavas Počepko <jp@webmaster.ms>
|
||||
Jason Del Ponte <delpontej@gmail.com>
|
||||
Jason Travis <infomaniac7@gmail.com>
|
||||
Jay Weisskopf <jay@jayschwa.net>
|
||||
Jeff Hodges <jeff@somethingsimilar.com>
|
||||
Jeff R. Allen <jra@nella.org>
|
||||
Jeff Sickel <jas@corpus-callosum.com>
|
||||
Jeff Wendling <jeff@spacemonkey.com>
|
||||
Jens Frederich <jfrederich@gmail.com>
|
||||
Jeremy Jackins <jeremyjackins@gmail.com>
|
||||
Jim McGrath <jimmc2@gmail.com>
|
||||
Jimmy Zelinskie <jimmyzelinskie@gmail.com>
|
||||
Jingcheng Zhang <diogin@gmail.com>
|
||||
Joakim Sernbrant <serbaut@gmail.com>
|
||||
Joe Poirier <jdpoirier@gmail.com>
|
||||
Joe Shaw <joe@joeshaw.org>
|
||||
Joel Stemmer <stemmertech@gmail.com>
|
||||
John Asmuth <jasmuth@gmail.com>
|
||||
John C Barstow <jbowtie@amathaine.com>
|
||||
John Graham-Cumming <jgc@jgc.org> <jgrahamc@gmail.com>
|
||||
John Howard Palevich <jack.palevich@gmail.com>
|
||||
John Shahid <jvshahid@gmail.com>
|
||||
John Tuley <john@tuley.org>
|
||||
Jonathan Gold <jgold.bg@gmail.com>
|
||||
Jonathan Mark <jhmark@xenops.com>
|
||||
Jonathan Rudenberg <jonathan@titanous.com>
|
||||
Jonathan Wills <runningwild@gmail.com>
|
||||
Jongmin Kim <atomaths@gmail.com>
|
||||
Jose Luis Vázquez González <josvazg@gmail.com>
|
||||
Joseph Holsten <joseph@josephholsten.com>
|
||||
Josh Bleecher Snyder <josharian@gmail.com>
|
||||
Josh Goebel <dreamer3@gmail.com>
|
||||
Josh Holland <jrh@joshh.co.uk>
|
||||
Joshua Chase <jcjoshuachase@gmail.com>
|
||||
JT Olds <jtolds@xnet5.com>
|
||||
Jukka-Pekka Kekkonen <karatepekka@gmail.com>
|
||||
Julian Phillips <julian@quantumfyre.co.uk>
|
||||
Julien Schmidt <google@julienschmidt.com>
|
||||
Kai Backman <kaib@golang.org>
|
||||
Kamil Kisiel <kamil@kamilkisiel.net> <kamil.kisiel@gmail.com>
|
||||
Katrina Owen <katrina.owen@gmail.com>
|
||||
Kei Son <hey.calmdown@gmail.com>
|
||||
Keith Rarick <kr@xph.us>
|
||||
Kelsey Hightower <kelsey.hightower@gmail.com>
|
||||
Kelvin Foo Chuan Lyi <vmirage@gmail.com>
|
||||
Ken Friedenbach <kenliz@cruzio.com>
|
||||
Ken Rockot <ken@oz.gs>
|
||||
Kevin Ballard <kevin@sb.org>
|
||||
Kyle Consalus <consalus@gmail.com>
|
||||
Kyle Isom <kyle@gokyle.net>
|
||||
Kyle Lemons <kyle@kylelemons.net>
|
||||
L Campbell <unpantsu@gmail.com>
|
||||
Lai Jiangshan <eag0628@gmail.com>
|
||||
Linaro Limited
|
||||
Lorenzo Stoakes <lstoakes@gmail.com>
|
||||
Luca Greco <luca.greco@alcacoop.it>
|
||||
Lucio De Re <lucio.dere@gmail.com>
|
||||
Luit van Drongelen <luitvd@gmail.com>
|
||||
Luka Zakrajšek <tr00.g33k@gmail.com>
|
||||
Luke Curley <qpingu@gmail.com>
|
||||
Manuel Mendez <mmendez534@gmail.com>
|
||||
Marc Weistroff <marc@weistroff.net>
|
||||
Marco Hennings <marco.hennings@freiheit.com>
|
||||
Mark Theunissen <mark.theunissen@gmail.com>
|
||||
Marko Juhani Silokunnas <marko.silokunnas@gmail.com>
|
||||
Marko Tiikkaja <marko@joh.to>
|
||||
Markover Inc. DBA Poptip
|
||||
Markus Duft <markus.duft@salomon.at>
|
||||
Markus Sonderegger <marraison@gmail.com>
|
||||
Markus Zimmermann <zimmski@gmail.com>
|
||||
Martin Neubauer <m.ne@gmx.net>
|
||||
Martin Olsson <martin@minimum.se>
|
||||
Mateusz Czapliński <czapkofan@gmail.com>
|
||||
Mathieu Lonjaret <mathieu.lonjaret@gmail.com>
|
||||
Mats Lidell <mats.lidell@cag.se>
|
||||
Matt Aimonetti <mattaimonetti@gmail.com>
|
||||
Matt Jibson <matt.jibson@gmail.com>
|
||||
Matt Joiner <anacrolix@gmail.com>
|
||||
Matt Reiferson <mreiferson@gmail.com>
|
||||
Matthew Cottingham <mattcottingham@gmail.com>
|
||||
Matthew Horsnell <matthew.horsnell@gmail.com>
|
||||
Maxim Khitrov <max@mxcrypt.com>
|
||||
Micah Stetson <micah.stetson@gmail.com>
|
||||
Michael Chaten <mchaten@gmail.com>
|
||||
Michael Elkins <michael.elkins@gmail.com>
|
||||
Michael Fraenkel <michael.fraenkel@gmail.com>
|
||||
Michael Gehring <mg@ebfe.org> <gnirheg.leahcim@gmail.com>
|
||||
Michael Hoisie <hoisie@gmail.com>
|
||||
Michael Lewis <mikelikespie@gmail.com>
|
||||
Michael MacInnis <Michael.P.MacInnis@gmail.com>
|
||||
Michael Pearson <mipearson@gmail.com>
|
||||
Michael Stapelberg <michael@stapelberg.de>
|
||||
Michael Teichgräber <mteichgraeber@gmx.de>
|
||||
Michał Derkacz <ziutek@lnet.pl>
|
||||
Miek Gieben <miek@miek.nl>
|
||||
Mihai Borobocea <MihaiBorobocea@gmail.com>
|
||||
Mikael Tillenius <mikti42@gmail.com>
|
||||
Mike Andrews <mra@xoba.com>
|
||||
Mike Rosset <mike.rosset@gmail.com>
|
||||
Mikhail Panchenko <m@mihasya.com>
|
||||
Miki Tebeka <miki.tebeka@gmail.com>
|
||||
Mikio Hara <mikioh.mikioh@gmail.com>
|
||||
Mikkel Krautz <mikkel@krautz.dk>
|
||||
Miquel Sabaté Solà <mikisabate@gmail.com>
|
||||
Moov Corporation
|
||||
Moriyoshi Koizumi <mozo@mozo.jp>
|
||||
Môshe van der Sterre <moshevds@gmail.com>
|
||||
Nan Deng <monnand@gmail.com>
|
||||
Nathan John Youngman <nj@nathany.com>
|
||||
Nathan P Finch <nate.finch@gmail.com>
|
||||
ngmoco, LLC
|
||||
Nicholas Katsaros <nick@nickkatsaros.com>
|
||||
Nicholas Presta <nick@nickpresta.ca> <nick1presta@gmail.com>
|
||||
Nicholas Sullivan <nicholas.sullivan@gmail.com>
|
||||
Nicholas Waples <nwaples@gmail.com>
|
||||
Nick Craig-Wood <nick@craig-wood.com> <nickcw@gmail.com>
|
||||
Nicolas Kaiser <nikai@nikai.net>
|
||||
Nicolas Owens <mischief@offblast.org>
|
||||
Nigel Kerr <nigel.kerr@gmail.com>
|
||||
Noah Campbell <noahcampbell@gmail.com>
|
||||
Oling Cat <olingcat@gmail.com>
|
||||
Oliver Hookins <ohookins@gmail.com>
|
||||
Olivier Antoine <olivier.antoine@gmail.com>
|
||||
Olivier Duperray <duperray.olivier@gmail.com>
|
||||
Olivier Saingre <osaingre@gmail.com>
|
||||
Padraig Kitterick <padraigkitterick@gmail.com>
|
||||
Paolo Giarrusso <p.giarrusso@gmail.com>
|
||||
Pascal S. de Kloe <pascal@quies.net>
|
||||
Patrick Crosby <patrick@stathat.com>
|
||||
Patrick Gavlin <pgavlin@gmail.com>
|
||||
Patrick Higgins <patrick.allen.higgins@gmail.com>
|
||||
Patrick Mézard <patrick@mezard.eu>
|
||||
Patrick Mylund Nielsen <patrick@patrickmn.com>
|
||||
Patrick Smith <pat42smith@gmail.com>
|
||||
Paul A Querna <paul.querna@gmail.com>
|
||||
Paul Hammond <paul@paulhammond.org>
|
||||
Paul Lalonde <paul.a.lalonde@gmail.com>
|
||||
Paul Sbarra <Sbarra.Paul@gmail.com>
|
||||
Paul van Brouwershaven <paul@vanbrouwershaven.com>
|
||||
Pavel Zinovkin <pavel.zinovkin@gmail.com>
|
||||
Percy Wegmann <ox.to.a.cart@gmail.com>
|
||||
Petar Maymounkov <petarm@gmail.com>
|
||||
Peter Armitage <peter.armitage@gmail.com>
|
||||
Peter Froehlich <peter.hans.froehlich@gmail.com>
|
||||
Peter Kleiweg <pkleiweg@xs4all.nl>
|
||||
Peter Mundy <go.peter.90@gmail.com>
|
||||
Péter Surányi <speter.go1@gmail.com>
|
||||
Péter Szilágyi <peterke@gmail.com>
|
||||
Peter Waller <peter.waller@gmail.com>
|
||||
Peter Williams <pwil3058@gmail.com>
|
||||
Philip K. Warren <pkwarren@gmail.com>
|
||||
Pieter Droogendijk <pieter@binky.org.uk>
|
||||
Pietro Gagliardi <pietro10@mac.com>
|
||||
Preetam Jinka <pj@preet.am>
|
||||
Quan Yong Zhai <qyzhai@gmail.com>
|
||||
Raif S. Naffah <go@naffah-raif.name>
|
||||
Red Hat, Inc.
|
||||
Rémy Oudompheng <oudomphe@phare.normalesup.org>
|
||||
Richard Crowley <r@rcrowley.org>
|
||||
Richard Eric Gavaletz <gavaletz@gmail.com>
|
||||
Richard Musiol <mail@richard-musiol.de>
|
||||
Rick Arnold <rickarnoldjr@gmail.com>
|
||||
Risto Jaakko Saarelma <rsaarelm@gmail.com>
|
||||
Robert Daniel Kortschak <dan.kortschak@adelaide.edu.au>
|
||||
Robert Dinu <r@varp.se>
|
||||
Robert Figueiredo <robfig@gmail.com>
|
||||
Robert Hencke <robert.hencke@gmail.com>
|
||||
Robert Obryk <robryk@gmail.com>
|
||||
Robin Eklind <r.eklind.87@gmail.com>
|
||||
Rodrigo Moraes de Oliveira <rodrigo.moraes@gmail.com>
|
||||
Rodrigo Rafael Monti Kochenburger <divoxx@gmail.com>
|
||||
Roger Pau Monné <royger@gmail.com>
|
||||
Roger Peppe <rogpeppe@gmail.com>
|
||||
Ron Hashimoto <mail@h2so5.net>
|
||||
Ron Minnich <rminnich@gmail.com>
|
||||
Ross Light <rlight2@gmail.com>
|
||||
Rowan Worth <sqweek@gmail.com>
|
||||
Ryan Hitchman <hitchmanr@gmail.com>
|
||||
Ryan Slade <ryanslade@gmail.com>
|
||||
S.Çağlar Onur <caglar@10ur.org>
|
||||
Sanjay Menakuru <balasanjay@gmail.com>
|
||||
Scott Ferguson <scottwferg@gmail.com>
|
||||
Scott Lawrence <bytbox@gmail.com>
|
||||
Sebastien Binet <seb.binet@gmail.com>
|
||||
Sébastien Paolacci <sebastien.paolacci@gmail.com>
|
||||
Sergei Skorobogatov <skorobo@rambler.ru>
|
||||
Sergey 'SnakE' Gromov <snake.scaly@gmail.com>
|
||||
Sergio Luis O. B. Correia <sergio@correia.cc>
|
||||
Shane Hansen <shanemhansen@gmail.com>
|
||||
Shawn Smith <shawn.p.smith@gmail.com>
|
||||
Shenghou Ma <minux.ma@gmail.com>
|
||||
Shivakumar GN <shivakumar.gn@gmail.com>
|
||||
Simon Whitehead <chemnova@gmail.com>
|
||||
Sokolov Yura <funny.falcon@gmail.com>
|
||||
Sergio Luis O. B. Correia <sergio@larces.uece.br>
|
||||
Spring Mc <heresy.mc@gmail.com>
|
||||
StalkR <stalkr@stalkr.net>
|
||||
Stefan Nilsson <snilsson@nada.kth.se> <trolleriprofessorn@gmail.com>
|
||||
Stéphane Travostino <stephane.travostino@gmail.com>
|
||||
Stephen McQuay <stephen@mcquay.me>
|
||||
Stefan Nilsson <snilsson@nada.kth.se>
|
||||
Stephen Weinberg <stephen@q5comm.com>
|
||||
Steve McCoy <mccoyst@gmail.com>
|
||||
Steven Elliot Harris <seharris@gmail.com>
|
||||
Steven Hartland <steven.hartland@multiplay.co.uk>
|
||||
Sven Almgren <sven@tras.se>
|
||||
Szabolcs Nagy <nsz@port70.net>
|
||||
Tad Glines <tad.glines@gmail.com>
|
||||
Taj Khattra <taj.khattra@gmail.com>
|
||||
Tarmigan Casebolt <tarmigan@gmail.com>
|
||||
Taru Karttunen <taruti@taruti.net>
|
||||
Tetsuo Kiso <tetsuokiso9@gmail.com>
|
||||
Thiago Fransosi Farina <thiago.farina@gmail.com>
|
||||
Thomas Alan Copeland <talan.copeland@gmail.com>
|
||||
Thomas Kappler <tkappler@gmail.com>
|
||||
Timo Savola <timo.savola@gmail.com>
|
||||
Timo Truyts <alkaloid.btx@gmail.com>
|
||||
Tobias Columbus <tobias.columbus@gmail.com>
|
||||
Tom Linford <tomlinford@gmail.com>
|
||||
Tor Andersson <tor.andersson@gmail.com>
|
||||
Travis Cline <travis.cline@gmail.com>
|
||||
Tudor Golubenco <tudor.g@gmail.com>
|
||||
Tw <tw19881113@gmail.com>
|
||||
Tyler Bunnell <tylerbunnell@gmail.com>
|
||||
Ugorji Nwoke <ugorji@gmail.com>
|
||||
Ulf Holm Nielsen <doktor@dyregod.dk>
|
||||
Uriel Mangado <uriel@berlinblue.org>
|
||||
Vadim Vygonets <unixdj@gmail.com>
|
||||
Vincent Ambo <tazjin@googlemail.com>
|
||||
Vincent Vanackere <vincent.vanackere@gmail.com>
|
||||
Vinu Rajashekhar <vinutheraj@gmail.com>
|
||||
Vladimir Nikishenko <vova616@gmail.com>
|
||||
Volker Dobler <dr.volker.dobler@gmail.com>
|
||||
Wei Guangjing <vcc.163@gmail.com>
|
||||
Willem van der Schyff <willemvds@gmail.com>
|
||||
William Josephson <wjosephson@gmail.com>
|
||||
William Orr <will@worrbase.com> <ay1244@gmail.com>
|
||||
Xia Bin <snyh@snyh.org>
|
||||
Xing Xing <mikespook@gmail.com>
|
||||
Yasuhiro Matsumoto <mattn.jp@gmail.com>
|
||||
Yissakhar Z. Beck <yissakhar.beck@gmail.com>
|
||||
Yongjian Xu <i3dmaster@gmail.com>
|
||||
Yoshiyuki Kanno <nekotaroh@gmail.com> <yoshiyuki.kanno@stoic.co.jp>
|
||||
Yusuke Kagiwada <block.rxckin.beats@gmail.com>
|
||||
Yuusei Kuwana <kuwana@kumama.org>
|
||||
Yuval Pavel Zholkover <paulzhol@gmail.com>
|
||||
Ziad Hatahet <hatahet@gmail.com>
|
||||
Zorion Arrizabalaga <zorionk@gmail.com>
|
||||
申习之 <bronze1man@gmail.com>
|
||||
|
||||
431
CONTRIBUTORS
@@ -31,593 +31,180 @@
|
||||
|
||||
# Please keep the list sorted.
|
||||
|
||||
Aaron France <aaron.l.france@gmail.com>
|
||||
Aaron Kemp <kemp.aaron@gmail.com>
|
||||
Abhinav Gupta <abhinav.g90@gmail.com>
|
||||
Adam Langley <agl@golang.org>
|
||||
Adrian Nos <nos.adrian@gmail.com>
|
||||
Adrian O'Grady <elpollouk@gmail.com>
|
||||
Adrien Bustany <adrien-xx-google@bustany.org>
|
||||
Ahmed Waheed Moanes <oneofone@gmail.com>
|
||||
Akshat Kumar <seed@mail.nanosouffle.net>
|
||||
Alan Donovan <adonovan@google.com>
|
||||
Alan Shreve <alan@inconshreveable.com>
|
||||
Albert Strasheim <fullung@gmail.com>
|
||||
Alberto Donizetti <alb.donizetti@gmail.com>
|
||||
Alberto García Hierro <alberto@garciahierro.com> <alberto.garcia.hierro@gmail.com>
|
||||
Aleksandar Dezelin <dezelin@gmail.com>
|
||||
Alex A Skinner <alex@lx.lc>
|
||||
Alex Brainman <alex.brainman@gmail.com>
|
||||
Alex Bramley <abramley@google.com>
|
||||
Alex Jin <toalexjin@gmail.com>
|
||||
Alexander Larsson <alexander.larsson@gmail.com>
|
||||
Alexander Orlov <alexander.orlov@loxal.net>
|
||||
Alexander Reece <awreece@gmail.com>
|
||||
Alexander Surma <surma@surmair.de>
|
||||
Alexander Zhavnerchik <alex.vizor@gmail.com>
|
||||
Alexandre Normand <alexandre.normand@gmail.com>
|
||||
Alexandru Moșoi <brtzsnr@gmail.com>
|
||||
Alexei Sholik <alcosholik@gmail.com>
|
||||
Alexey Borzenkov <snaury@gmail.com>
|
||||
Alexey Palazhchenko <alexey.palazhchenko@gmail.com>
|
||||
Alexis Imperial-Legrand <ail@google.com>
|
||||
Amir Mohammad Saied <amir@gluegadget.com>
|
||||
Amrut Joshi <amrut.joshi@gmail.com>
|
||||
Andrea Spadaccini <spadaccio@google.com>
|
||||
Andreas Jellinghaus <andreas@ionisiert.de> <anj@google.com>
|
||||
Andrei Vieru <euvieru@gmail.com>
|
||||
Andres Erbsen <andreser@google.com>
|
||||
Andrew Balholm <andybalholm@gmail.com>
|
||||
Andrew Bonventre <andybons@chromium.org>
|
||||
Andrew Bursavich <abursavich@gmail.com>
|
||||
Andrew Gerrand <adg@golang.org>
|
||||
Andrew Harding <andrew@spacemonkey.com>
|
||||
Andrew Lutomirski <andy@luto.us>
|
||||
Andrew Pritchard <awpritchard@gmail.com>
|
||||
Andrew Radev <andrey.radev@gmail.com>
|
||||
Andrew Skiba <skibaa@gmail.com>
|
||||
Andrew Szeto <andrew@jabagawee.com>
|
||||
Andrew Wilkins <axwalk@gmail.com>
|
||||
Andrey Mirtchovski <mirtchovski@gmail.com>
|
||||
Andriy Lytvynov <lytvynov.a.v@gmail.com>
|
||||
Andy Davis <andy@bigandian.com>
|
||||
Anfernee Yongkun Gui <anfernee.gui@gmail.com>
|
||||
Anh Hai Trinh <anh.hai.trinh@gmail.com>
|
||||
Anschel Schaffer-Cohen <anschelsc@gmail.com>
|
||||
Anthony Eufemio <anthony.eufemio@gmail.com>
|
||||
Anthony Martin <ality@pbrane.org>
|
||||
Anthony Starks <ajstarks@gmail.com>
|
||||
Apisak Darakananda <pongad@gmail.com>
|
||||
Aram Hăvărneanu <aram@mgk.ro>
|
||||
Arnaud Ysmal <arnaud.ysmal@gmail.com>
|
||||
Arne Hormann <arnehormann@gmail.com>
|
||||
Aron Nopanen <aron.nopanen@gmail.com>
|
||||
Arvindh Rajesh Tamilmani <art@a-30.net>
|
||||
Asim Shankar <asimshankar@gmail.com>
|
||||
Ato Araki <ato.araki@gmail.com>
|
||||
Aulus Egnatius Varialus <varialus@gmail.com>
|
||||
Austin Clements <austin@google.com> <aclements@csail.mit.edu>
|
||||
Austin Clements <aclements@csail.mit.edu>
|
||||
Balazs Lecz <leczb@google.com>
|
||||
Ben Eitzen <eitzenb@golang.org>
|
||||
Ben Fried <ben.fried@gmail.com>
|
||||
Ben Lynn <benlynn@gmail.com>
|
||||
Ben Olive <sionide21@gmail.com>
|
||||
Benjamin Black <b@b3k.us>
|
||||
Benny Siegert <bsiegert@gmail.com>
|
||||
Benoit Sigoure <tsunanet@gmail.com>
|
||||
Berengar Lehr <Berengar.Lehr@gmx.de>
|
||||
Bill Neubauer <wcn@golang.org> <wcn@google.com> <bill.neubauer@gmail.com>
|
||||
Bill Thiede <couchmoney@gmail.com>
|
||||
Billie Harold Cleek <bhcleek@gmail.com>
|
||||
Bjorn Tillenius <bjorn@tillenius.me>
|
||||
Bjorn Tipling <bjorn.tipling@gmail.com>
|
||||
Blake Mizerany <blake.mizerany@gmail.com>
|
||||
Bobby Powers <bobbypowers@gmail.com>
|
||||
Bill Neubauer <wcn@golang.org> <wcn@google.com>
|
||||
Brad Fitzpatrick <bradfitz@golang.org> <bradfitz@gmail.com>
|
||||
Brad Garcia <bgarcia@golang.org>
|
||||
Brendan Daniel Tracey <tracey.brendan@gmail.com>
|
||||
Brendan O'Dea <bod@golang.org>
|
||||
Brian Dellisanti <briandellisanti@gmail.com>
|
||||
Brian G. Merrell <bgmerrell@gmail.com>
|
||||
Brian Gitonga Marete <marete@toshnix.com>
|
||||
Brian Ketelsen <bketelsen@gmail.com>
|
||||
Brian Slesinsky <skybrian@google.com>
|
||||
Burcu Dogan <jbd@google.com>
|
||||
Caine Tighe <arctanofyourface@gmail.com>
|
||||
Caleb Spare <cespare@gmail.com>
|
||||
Carl Chatfield <carlchatfield@gmail.com>
|
||||
Carl Mastrangelo <notcarl@google.com>
|
||||
Carl Shapiro <cshapiro@google.com> <cshapiro@golang.org>
|
||||
Carlos Castillo <cookieo9@gmail.com>
|
||||
Cary Hull <chull@google.com>
|
||||
Case Nelson <case.nelson@gmail.com>
|
||||
Casey Marshall <casey.marshall@gmail.com>
|
||||
Catalin Patulea <catalinp@google.com>
|
||||
Cezar Sá Espinola <cezarsa@gmail.com>
|
||||
ChaiShushan <chaishushan@gmail.com>
|
||||
Charles L. Dorian <cldorian@gmail.com>
|
||||
Charles Lee <zombie.fml@gmail.com>
|
||||
Chris Dollin <ehog.hedge@gmail.com>
|
||||
Chris Farmiloe <chrisfarms@gmail.com>
|
||||
Chris Howey <howeyc@gmail.com>
|
||||
Chris Hundt <hundt@google.com>
|
||||
Chris Jones <chris@cjones.org> <chris.jones.yar@gmail.com>
|
||||
Chris Lennert <calennert@gmail.com>
|
||||
Chris Manghane <cmang@golang.org>
|
||||
Chris McGee <sirnewton_01@yahoo.ca> <newton688@gmail.com>
|
||||
Christian Himpel <chressie@googlemail.com> <chressie@gmail.com>
|
||||
Christine Hansmann <chhansmann@gmail.com>
|
||||
Christoffer Buchholz <christoffer.buchholz@gmail.com>
|
||||
Christoph Hack <christoph@tux21b.org>
|
||||
Christopher Cahoon <chris.cahoon@gmail.com>
|
||||
Christopher Nielsen <m4dh4tt3r@gmail.com>
|
||||
Christopher Redden <christopher.redden@gmail.com>
|
||||
Christopher Swenson <cswenson@google.com>
|
||||
Christopher Wedgwood <cw@f00f.org>
|
||||
Clement Skau <clementskau@gmail.com>
|
||||
Colby Ranger <cranger@google.com>
|
||||
Conrad Meyer <cemeyer@cs.washington.edu>
|
||||
Corey Thomasson <cthom.lists@gmail.com>
|
||||
Cosmos Nicolaou <cnicolaou@google.com>
|
||||
Cristian Staretu <unclejacksons@gmail.com>
|
||||
Damian Gryski <dgryski@gmail.com>
|
||||
Damien Neil <dneil@google.com>
|
||||
Dan Callahan <dan.callahan@gmail.com>
|
||||
Dan Peterson <dpiddy@gmail.com>
|
||||
Dan Sinclair <dan.sinclair@gmail.com>
|
||||
Daniel Fleischman <danielfleischman@gmail.com>
|
||||
Daniel Krech <eikeon@eikeon.com>
|
||||
Daniel Lidén <daniel.liden.87@gmail.com>
|
||||
Daniel Morsing <daniel.morsing@gmail.com>
|
||||
Daniel Nadasi <dnadasi@google.com>
|
||||
Daniel Theophanes <kardianos@gmail.com>
|
||||
Darren Elwood <darren@textnode.com>
|
||||
Dave Borowitz <dborowitz@google.com>
|
||||
Dave Cheney <dave@cheney.net>
|
||||
Dave Day <djd@golang.org>
|
||||
Dave Grijalva <dgrijalva@ngmoco.com>
|
||||
David Anderson <danderson@google.com>
|
||||
David Barnett <dbarnett@google.com>
|
||||
David Bürgin <676c7473@gmail.com>
|
||||
David Calavera <david.calavera@gmail.com>
|
||||
David Covert <davidhcovert@gmail.com>
|
||||
David Crawshaw <david.crawshaw@zentus.com> <crawshaw@google.com> <crawshaw@golang.org>
|
||||
David du Colombier <0intro@gmail.com>
|
||||
David Crawshaw <david.crawshaw@zentus.com>
|
||||
David Forsythe <dforsythe@gmail.com>
|
||||
David G. Andersen <dave.andersen@gmail.com>
|
||||
David Jakob Fritz <david.jakob.fritz@gmail.com>
|
||||
David Leon Gil <coruus@gmail.com>
|
||||
David McLeish <davemc@google.com>
|
||||
David Presotto <presotto@gmail.com>
|
||||
David Symonds <dsymonds@golang.org>
|
||||
David Thomas <davidthomas426@gmail.com>
|
||||
David Titarenco <david.titarenco@gmail.com>
|
||||
Dean Prichard <dean.prichard@gmail.com>
|
||||
Denis Brandolini <denis.brandolini@gmail.com>
|
||||
Derek Parker <parkerderek86@gmail.com>
|
||||
Devon H. O'Dell <devon.odell@gmail.com>
|
||||
Dhiru Kholia <dhiru.kholia@gmail.com>
|
||||
Dimitri Tcaciuc <dtcaciuc@gmail.com>
|
||||
Dmitri Shuralyov <shurcooL@gmail.com>
|
||||
Dmitriy Shelenin <deemok@googlemail.com> <deemok@gmail.com>
|
||||
Dmitriy Vyukov <dvyukov@google.com>
|
||||
Dmitry Chestnykh <dchest@gmail.com>
|
||||
Dominik Honnef <dominik.honnef@gmail.com>
|
||||
Donovan Hide <donovanhide@gmail.com>
|
||||
Drew Hintz <adhintz@google.com>
|
||||
Duncan Holm <mail@frou.org>
|
||||
Dustin Long <dustmop@gmail.com>
|
||||
Dustin Sallings <dsallings@gmail.com>
|
||||
Dustin Shields-Cloues <dcloues@gmail.com>
|
||||
Eden Li <eden.li@gmail.com>
|
||||
Egon Elbre <egonelbre@gmail.com>
|
||||
Ehren Kret <ehren.kret@gmail.com>
|
||||
Eivind Uggedal <eivind@uggedal.com>
|
||||
Elias Naur <elias.naur@gmail.com>
|
||||
Emil Hessman <c.emil.hessman@gmail.com>
|
||||
Eoghan Sherry <ejsherry@gmail.com>
|
||||
Eric Clark <zerohp@gmail.com>
|
||||
Eric Milliken <emilliken@gmail.com>
|
||||
Eric Roshan-Eisner <eric.d.eisner@gmail.com>
|
||||
Erik St. Martin <alakriti@gmail.com>
|
||||
Erik Westrup <erik.westrup@gmail.com>
|
||||
Esko Luontola <esko.luontola@gmail.com>
|
||||
Evan Kroske <evankroske@google.com>
|
||||
Evan Martin <evan.martin@gmail.com>
|
||||
Eric Eisner <eric.d.eisner@gmail.com>
|
||||
Evan Shaw <chickencha@gmail.com>
|
||||
Ewan Chou <coocood@gmail.com>
|
||||
Fabrizio Milo <mistobaan@gmail.com>
|
||||
Fan Hongjian <fan.howard@gmail.com>
|
||||
Fatih Arslan <fatih@arslan.io>
|
||||
Fazlul Shahriar <fshahriar@gmail.com>
|
||||
Felix Geisendörfer <haimuiba@gmail.com>
|
||||
Firmansyah Adiputra <frm.adiputra@gmail.com>
|
||||
Florian Uekermann <florian@uekermann-online.de> <f1@uekermann-online.de>
|
||||
Florian Weimer <fw@deneb.enyo.de>
|
||||
Folke Behrens <folke@google.com>
|
||||
Francesc Campoy <campoy@golang.org>
|
||||
Francisco Souza <franciscossouza@gmail.com>
|
||||
Frederick Kelly Mayle III <frederickmayle@gmail.com>
|
||||
Fredrik Enestad <fredrik.enestad@soundtrackyourbrand.com>
|
||||
Frithjof Schulze <schulze@math.uni-hannover.de> <sfrithjof@gmail.com>
|
||||
Fumitoshi Ukai <ukai@google.com>
|
||||
Gaal Yahas <gaal@google.com>
|
||||
Gabriel Aszalos <gabriel.aszalos@gmail.com>
|
||||
Gary Burd <gary@beagledreams.com> <gary.burd@gmail.com>
|
||||
Gautham Thambidorai <gautham.dorai@gmail.com>
|
||||
Georg Reinke <guelfey@gmail.com>
|
||||
Gerasimos Dimitriadis <gedimitr@gmail.com>
|
||||
Gideon Jan-Wessel Redelinghuys <gjredelinghuys@gmail.com>
|
||||
Giles Lean <giles.lean@pobox.com>
|
||||
Glenn Lewis <gmlewis@google.com>
|
||||
Gordon Klaus <gordon.klaus@gmail.com>
|
||||
Graham King <graham4king@gmail.com>
|
||||
Graham Miller <graham.miller@gmail.com>
|
||||
Greg Ward <greg@gerg.ca>
|
||||
Guillaume J. Charmes <guillaume@charmes.net>
|
||||
Gustav Paul <gustav.paul@gmail.com>
|
||||
Gustavo Franco <gustavorfranco@gmail.com>
|
||||
Gustavo Niemeyer <gustavo@niemeyer.net> <n13m3y3r@gmail.com>
|
||||
Gwenael Treguier <gwenn.kahz@gmail.com>
|
||||
Hana Kim <hyangah@gmail.com>
|
||||
Han-Wen Nienhuys <hanwen@google.com>
|
||||
Harley Laue <losinggeneration@gmail.com>
|
||||
Hector Chu <hectorchu@gmail.com>
|
||||
Hector Martin Cantero <hector@marcansoft.com>
|
||||
Henning Schmiedehausen <henning@schmiedehausen.org>
|
||||
Henrik Edwards <henrik.edwards@gmail.com>
|
||||
Herbert Georg Fischer <herbert.fischer@gmail.com>
|
||||
Hong Ruiqi <hongruiqi@gmail.com>
|
||||
Hossein Sheikh Attar <hattar@google.com>
|
||||
Ian Lance Taylor <iant@golang.org>
|
||||
Icarus Sparry <golang@icarus.freeuk.com>
|
||||
Ingo Oeser <nightlyone@googlemail.com> <nightlyone@gmail.com>
|
||||
Isaac Wagner <ibw@isaacwagner.me>
|
||||
Ivan Krasin <krasin@golang.org>
|
||||
Jacob Baskin <jbaskin@google.com>
|
||||
Jakob Borg <jakob@nym.se>
|
||||
Jakub Ryszard Czarnowicz <j.czarnowicz@gmail.com>
|
||||
James Aguilar <jaguilar@google.com>
|
||||
James David Chalfant <james.chalfant@gmail.com>
|
||||
James Fysh <james.fysh@gmail.com>
|
||||
James Gray <james@james4k.com>
|
||||
James Meneghello <rawrz0r@gmail.com>
|
||||
James P. Cooper <jamespcooper@gmail.com>
|
||||
James Robinson <jamesr@google.com> <jamesr.gatech@gmail.com>
|
||||
James Toy <nil@opensesame.st>
|
||||
James Tucker <raggi@google.com>
|
||||
James Whitehead <jnwhiteh@gmail.com>
|
||||
Jamie Gennis <jgennis@google.com> <jgennis@gmail.com>
|
||||
Jamie Turner <jamwt@dropbox.com>
|
||||
Jamie Wilkinson <jaq@spacepants.org>
|
||||
Jamie Gennis <jgennis@google.com>
|
||||
Jan H. Hosang <jan.hosang@gmail.com>
|
||||
Jan Mercl <0xjnml@gmail.com>
|
||||
Jan Mercl <befelemepeseveze@gmail.com>
|
||||
Jan Newmarch <jan.newmarch@gmail.com>
|
||||
Jan Ziak <0xe2.0x9a.0x9b@gmail.com>
|
||||
Jani Monoses <jani.monoses@ubuntu.com> <jani.monoses@gmail.com>
|
||||
Jaroslavas Počepko <jp@webmaster.ms>
|
||||
Jason Del Ponte <delpontej@gmail.com>
|
||||
Jason Travis <infomaniac7@gmail.com>
|
||||
Jay Weisskopf <jay@jayschwa.net>
|
||||
Jean-Marc Eurin <jmeurin@google.com>
|
||||
Jed Denlea <jed@fastly.com>
|
||||
Jeff Hodges <jeff@somethingsimilar.com>
|
||||
Jeff R. Allen <jra@nella.org> <jeff.allen@gmail.com>
|
||||
Jeff Sickel <jas@corpus-callosum.com>
|
||||
Jeff Wendling <jeff@spacemonkey.com>
|
||||
Jens Frederich <jfrederich@gmail.com>
|
||||
Jeremiah Harmsen <jeremiah@google.com>
|
||||
Jeremy Jackins <jeremyjackins@gmail.com>
|
||||
Jeremy Schlatter <jeremy.schlatter@gmail.com>
|
||||
Jim McGrath <jimmc2@gmail.com>
|
||||
Jimmy Zelinskie <jimmyzelinskie@gmail.com>
|
||||
Jingcheng Zhang <diogin@gmail.com>
|
||||
Joakim Sernbrant <serbaut@gmail.com>
|
||||
Joe Poirier <jdpoirier@gmail.com>
|
||||
Joe Shaw <joe@joeshaw.org>
|
||||
Joel Sing <jsing@google.com>
|
||||
Joel Stemmer <stemmertech@gmail.com>
|
||||
Johan Euphrosine <proppy@google.com>
|
||||
John Asmuth <jasmuth@gmail.com>
|
||||
John Beisley <huin@google.com>
|
||||
John C Barstow <jbowtie@amathaine.com>
|
||||
John DeNero <denero@google.com>
|
||||
John Graham-Cumming <jgc@jgc.org> <jgrahamc@gmail.com>
|
||||
John Howard Palevich <jack.palevich@gmail.com>
|
||||
John Newlin <jnewlin@google.com>
|
||||
John Shahid <jvshahid@gmail.com>
|
||||
John Tuley <john@tuley.org>
|
||||
Jonathan Allie <jonallie@google.com>
|
||||
Jonathan Feinberg <feinberg@google.com>
|
||||
Jonathan Gold <jgold.bg@gmail.com>
|
||||
Jonathan Hseu <jhseu@google.com>
|
||||
Jonathan Mark <jhmark@xenops.com> <jhmark000@gmail.com>
|
||||
Jonathan Nieder <jrn@google.com>
|
||||
Jonathan Pittman <jmpittman@google.com> <jonathan.mark.pittman@gmail.com>
|
||||
Jonathan Rudenberg <jonathan@titanous.com>
|
||||
Jonathan Wills <runningwild@gmail.com>
|
||||
Jongmin Kim <atomaths@gmail.com>
|
||||
Jos Visser <josv@google.com>
|
||||
Jose Luis Vázquez González <josvazg@gmail.com>
|
||||
Joseph Bonneau <jcb@google.com>
|
||||
Joseph Holsten <joseph@josephholsten.com>
|
||||
Josh Bleecher Snyder <josharian@gmail.com>
|
||||
Josh Goebel <dreamer3@gmail.com>
|
||||
Josh Hoak <jhoak@google.com>
|
||||
Josh Holland <jrh@joshh.co.uk>
|
||||
Joshua Chase <jcjoshuachase@gmail.com>
|
||||
JP Sugarbroad <jpsugar@google.com>
|
||||
JT Olds <jtolds@xnet5.com>
|
||||
Jukka-Pekka Kekkonen <karatepekka@gmail.com>
|
||||
Julian Phillips <julian@quantumfyre.co.uk>
|
||||
Julien Schmidt <google@julienschmidt.com>
|
||||
Kai Backman <kaib@golang.org>
|
||||
Kamil Kisiel <kamil@kamilkisiel.net> <kamil.kisiel@gmail.com>
|
||||
Katrina Owen <katrina.owen@gmail.com>
|
||||
Kay Zhu <kayzhu@google.com>
|
||||
Kei Son <hey.calmdown@gmail.com>
|
||||
Keith Randall <khr@golang.org>
|
||||
Keith Rarick <kr@xph.us>
|
||||
Kelsey Hightower <kelsey.hightower@gmail.com>
|
||||
Kelvin Foo Chuan Lyi <vmirage@gmail.com>
|
||||
Ken Friedenbach <kenliz@cruzio.com>
|
||||
Ken Rockot <ken@oz.gs> <ken.rockot@gmail.com>
|
||||
Ken Thompson <ken@golang.org>
|
||||
Kevin Ballard <kevin@sb.org>
|
||||
Kevin Klues <klueska@gmail.com> <klueska@google.com>
|
||||
Kirklin McDonald <kirklin.mcdonald@gmail.com>
|
||||
Kyle Consalus <consalus@gmail.com>
|
||||
Kyle Isom <kyle@gokyle.net>
|
||||
Kyle Lemons <kyle@kylelemons.net> <kevlar@google.com>
|
||||
L Campbell <unpantsu@gmail.com>
|
||||
Lai Jiangshan <eag0628@gmail.com>
|
||||
Kyle Lemons <kyle@kylelemons.net> <etherealflaim@gmail.com>
|
||||
Larry Hosken <lahosken@golang.org>
|
||||
Lorenzo Stoakes <lstoakes@gmail.com>
|
||||
Louis Kruger <louisk@google.com>
|
||||
Luca Greco <luca.greco@alcacoop.it>
|
||||
Lucio De Re <lucio.dere@gmail.com>
|
||||
Luit van Drongelen <luitvd@gmail.com>
|
||||
Luka Zakrajšek <tr00.g33k@gmail.com>
|
||||
Luke Curley <qpingu@gmail.com>
|
||||
Luuk van Dijk <lvd@golang.org> <lvd@google.com>
|
||||
Manoj Dayaram <platform-dev@moovweb.com> <manoj.dayaram@moovweb.com>
|
||||
Manu Garg <manugarg@google.com>
|
||||
Manuel Mendez <mmendez534@gmail.com>
|
||||
Marc Weistroff <marc@weistroff.net>
|
||||
Marcel van Lohuizen <mpvl@golang.org>
|
||||
Marco Hennings <marco.hennings@freiheit.com>
|
||||
Mark Theunissen <mark.theunissen@gmail.com>
|
||||
Mark Zavislak <zavislak@google.com>
|
||||
Marko Juhani Silokunnas <marko.silokunnas@gmail.com>
|
||||
Marko Mikulicic <mkm@google.com>
|
||||
Marko Tiikkaja <marko@joh.to>
|
||||
Markus Duft <markus.duft@salomon.at>
|
||||
Markus Sonderegger <marraison@gmail.com>
|
||||
Markus Zimmermann <zimmski@gmail.com>
|
||||
Martin Neubauer <m.ne@gmx.net>
|
||||
Martin Olsson <martin@minimum.se>
|
||||
Mateusz Czapliński <czapkofan@gmail.com>
|
||||
Mathieu Lonjaret <mathieu.lonjaret@gmail.com>
|
||||
Mats Lidell <mats.lidell@cag.se> <mats.lidell@gmail.com>
|
||||
Matt Aimonetti <mattaimonetti@gmail.com>
|
||||
Matt Brown <mdbrown@google.com>
|
||||
Matt Jibson <matt.jibson@gmail.com>
|
||||
Matt Joiner <anacrolix@gmail.com>
|
||||
Matt Jones <mrjones@google.com>
|
||||
Matt Reiferson <mreiferson@gmail.com>
|
||||
Matthew Cottingham <mattcottingham@gmail.com>
|
||||
Matthew Dempsky <mdempsky@google.com>
|
||||
Matthew Horsnell <matthew.horsnell@gmail.com>
|
||||
Maxim Khitrov <max@mxcrypt.com>
|
||||
Maxim Pimenov <mpimenov@google.com>
|
||||
Maxim Ushakov <ushakov@google.com>
|
||||
Micah Stetson <micah.stetson@gmail.com>
|
||||
Michael Chaten <mchaten@gmail.com>
|
||||
Michael Elkins <michael.elkins@gmail.com>
|
||||
Michael Fraenkel <michael.fraenkel@gmail.com>
|
||||
Michael Gehring <mg@ebfe.org> <gnirheg.leahcim@gmail.com>
|
||||
Michael Hoisie <hoisie@gmail.com>
|
||||
Michael Hudson-Doyle <michael.hudson@linaro.org>
|
||||
Michael Kelly <mjk@google.com>
|
||||
Michael Lewis <mikelikespie@gmail.com>
|
||||
Michael MacInnis <Michael.P.MacInnis@gmail.com>
|
||||
Michael Matloob <matloob@google.com>
|
||||
Michael Pearson <mipearson@gmail.com>
|
||||
Michael Piatek <piatek@google.com>
|
||||
Michael Shields <mshields@google.com>
|
||||
Michael Stapelberg <michael@stapelberg.de> <mstplbrg@googlemail.com>
|
||||
Michael T. Jones <mtj@google.com> <michael.jones@gmail.com>
|
||||
Michael Teichgräber <mteichgraeber@gmx.de> <mt4swm@googlemail.com>
|
||||
Michał Derkacz <ziutek@lnet.pl>
|
||||
Miek Gieben <miek@miek.nl> <remigius.gieben@gmail.com>
|
||||
Mihai Borobocea <MihaiBorobocea@gmail.com>
|
||||
Mikael Tillenius <mikti42@gmail.com>
|
||||
Mike Andrews <mra@xoba.com>
|
||||
Mike Rosset <mike.rosset@gmail.com>
|
||||
Mike Samuel <mikesamuel@gmail.com>
|
||||
Mike Solomon <msolo@gmail.com>
|
||||
Mikhail Panchenko <m@mihasya.com>
|
||||
Miki Tebeka <miki.tebeka@gmail.com>
|
||||
Mikio Hara <mikioh.mikioh@gmail.com>
|
||||
Mikkel Krautz <mikkel@krautz.dk> <krautz@gmail.com>
|
||||
Miquel Sabaté Solà <mikisabate@gmail.com>
|
||||
Moriyoshi Koizumi <mozo@mozo.jp>
|
||||
Môshe van der Sterre <moshevds@gmail.com>
|
||||
Mrunal Patel <mrunalp@gmail.com>
|
||||
Nan Deng <monnand@gmail.com>
|
||||
Nathan John Youngman <nj@nathany.com>
|
||||
Nathan P Finch <nate.finch@gmail.com>
|
||||
Nicholas Katsaros <nick@nickkatsaros.com>
|
||||
Nicholas Presta <nick@nickpresta.ca> <nick1presta@gmail.com>
|
||||
Nicholas Sullivan <nicholas.sullivan@gmail.com>
|
||||
Nicholas Waples <nwaples@gmail.com>
|
||||
Nick Craig-Wood <nick@craig-wood.com> <nickcw@gmail.com>
|
||||
Nicolas Kaiser <nikai@nikai.net>
|
||||
Nicolas Owens <mischief@offblast.org>
|
||||
Nigel Kerr <nigel.kerr@gmail.com>
|
||||
Nigel Tao <nigeltao@golang.org>
|
||||
Noah Campbell <noahcampbell@gmail.com>
|
||||
Oling Cat <olingcat@gmail.com>
|
||||
Oliver Hookins <ohookins@gmail.com>
|
||||
Olivier Antoine <olivier.antoine@gmail.com>
|
||||
Olivier Duperray <duperray.olivier@gmail.com>
|
||||
Olivier Saingre <osaingre@gmail.com>
|
||||
Padraig Kitterick <padraigkitterick@gmail.com>
|
||||
Paolo Giarrusso <p.giarrusso@gmail.com>
|
||||
Pascal S. de Kloe <pascal@quies.net>
|
||||
Patrick Crosby <patrick@stathat.com>
|
||||
Patrick Gavlin <pgavlin@gmail.com>
|
||||
Patrick Higgins <patrick.allen.higgins@gmail.com>
|
||||
Patrick Mézard <patrick@mezard.eu>
|
||||
Patrick Mylund Nielsen <patrick@patrickmn.com>
|
||||
Patrick Riley <pfr@google.com>
|
||||
Patrick Smith <pat42smith@gmail.com>
|
||||
Paul A Querna <paul.querna@gmail.com>
|
||||
Paul Borman <borman@google.com>
|
||||
Paul Chang <paulchang@google.com>
|
||||
Paul Hammond <paul@paulhammond.org>
|
||||
Paul Lalonde <paul.a.lalonde@gmail.com>
|
||||
Paul Nasrat <pnasrat@google.com>
|
||||
Paul Sbarra <Sbarra.Paul@gmail.com>
|
||||
Paul van Brouwershaven <paul@vanbrouwershaven.com>
|
||||
Pavel Zinovkin <pavel.zinovkin@gmail.com>
|
||||
Pawel Szczur <filemon@google.com>
|
||||
Percy Wegmann <ox.to.a.cart@gmail.com>
|
||||
Petar Maymounkov <petarm@gmail.com>
|
||||
Peter Armitage <peter.armitage@gmail.com>
|
||||
Peter Collingbourne <pcc@google.com>
|
||||
Peter Froehlich <peter.hans.froehlich@gmail.com>
|
||||
Peter Kleiweg <pkleiweg@xs4all.nl>
|
||||
Peter McKenzie <petermck@google.com>
|
||||
Peter Mundy <go.peter.90@gmail.com>
|
||||
Péter Surányi <speter.go1@gmail.com>
|
||||
Péter Szabó <pts@google.com>
|
||||
Péter Szilágyi <peterke@gmail.com>
|
||||
Peter Waller <peter.waller@gmail.com>
|
||||
Peter Weinberger <pjw@golang.org>
|
||||
Peter Williams <pwil3058@gmail.com>
|
||||
Phil Pennock <pdp@golang.org>
|
||||
Philip K. Warren <pkwarren@gmail.com>
|
||||
Pieter Droogendijk <pieter@binky.org.uk>
|
||||
Pietro Gagliardi <pietro10@mac.com>
|
||||
Preetam Jinka <pj@preet.am>
|
||||
Quan Yong Zhai <qyzhai@gmail.com>
|
||||
Raif S. Naffah <go@naffah-raif.name>
|
||||
Raph Levien <raph@google.com>
|
||||
Raul Silvera <rsilvera@google.com>
|
||||
Rémy Oudompheng <oudomphe@phare.normalesup.org> <remyoudompheng@gmail.com>
|
||||
Richard Crowley <r@rcrowley.org>
|
||||
Richard Eric Gavaletz <gavaletz@gmail.com>
|
||||
Richard Musiol <mail@richard-musiol.de> <neelance@gmail.com>
|
||||
Rick Arnold <rickarnoldjr@gmail.com>
|
||||
Rick Hudson <rlh@golang.org>
|
||||
Risto Jaakko Saarelma <rsaarelm@gmail.com>
|
||||
Rob Pike <r@golang.org>
|
||||
Robert Daniel Kortschak <dan.kortschak@adelaide.edu.au>
|
||||
Robert Dinu <r@varp.se>
|
||||
Robert Figueiredo <robfig@gmail.com>
|
||||
Robert Griesemer <gri@golang.org>
|
||||
Robert Hencke <robert.hencke@gmail.com>
|
||||
Robert Obryk <robryk@gmail.com>
|
||||
Robert Sesek <rsesek@google.com>
|
||||
Robert Snedegar <roberts@google.com>
|
||||
Robin Eklind <r.eklind.87@gmail.com>
|
||||
Rodrigo Moraes de Oliveira <rodrigo.moraes@gmail.com>
|
||||
Rodrigo Rafael Monti Kochenburger <divoxx@gmail.com>
|
||||
Roger Pau Monné <royger@gmail.com>
|
||||
Roger Peppe <rogpeppe@gmail.com>
|
||||
Ron Hashimoto <mail@h2so5.net>
|
||||
Ron Minnich <rminnich@gmail.com>
|
||||
Ross Light <rlight2@gmail.com>
|
||||
Rowan Worth <sqweek@gmail.com>
|
||||
Rui Ueyama <ruiu@google.com>
|
||||
Russ Cox <rsc@golang.org>
|
||||
Ryan Barrett <ryanb@google.com>
|
||||
Ryan Hitchman <hitchmanr@gmail.com>
|
||||
Ryan Slade <ryanslade@gmail.com>
|
||||
S.Çağlar Onur <caglar@10ur.org>
|
||||
Sam Thorogood <thorogood@google.com> <sam.thorogood@gmail.com>
|
||||
Sameer Ajmani <sameer@golang.org> <ajmani@gmail.com>
|
||||
Sanjay Menakuru <balasanjay@gmail.com>
|
||||
Scott Ferguson <scottwferg@gmail.com>
|
||||
Sameer Ajmani <ajmani@gmail.com>
|
||||
Scott Lawrence <bytbox@gmail.com>
|
||||
Scott Schwartz <scotts@golang.org>
|
||||
Sean Burford <sburford@google.com>
|
||||
Sebastien Binet <seb.binet@gmail.com>
|
||||
Sébastien Paolacci <sebastien.paolacci@gmail.com>
|
||||
Sergei Skorobogatov <skorobo@rambler.ru>
|
||||
Sergey 'SnakE' Gromov <snake.scaly@gmail.com>
|
||||
Sergio Luis O. B. Correia <sergio@correia.cc>
|
||||
Shane Hansen <shanemhansen@gmail.com>
|
||||
Shawn Ledbetter <sledbetter@google.com>
|
||||
Shawn Smith <shawn.p.smith@gmail.com>
|
||||
Shenghou Ma <minux@golang.org> <minux.ma@gmail.com>
|
||||
Shivakumar GN <shivakumar.gn@gmail.com>
|
||||
Simon Whitehead <chemnova@gmail.com>
|
||||
Sokolov Yura <funny.falcon@gmail.com>
|
||||
Sergio Luis O. B. Correia <sergio@larces.uece.br>
|
||||
Spring Mc <heresy.mc@gmail.com>
|
||||
StalkR <stalkr@stalkr.net>
|
||||
Stefan Nilsson <snilsson@nada.kth.se> <trolleriprofessorn@gmail.com>
|
||||
Stéphane Travostino <stephane.travostino@gmail.com>
|
||||
Stefan Nilsson <snilsson@nada.kth.se>
|
||||
Stephen Ma <stephenm@golang.org>
|
||||
Stephen McQuay <stephen@mcquay.me>
|
||||
Stephen Weinberg <stephen@q5comm.com>
|
||||
Steve McCoy <mccoyst@gmail.com>
|
||||
Steven Elliot Harris <seharris@gmail.com>
|
||||
Steven Hartland <steven.hartland@multiplay.co.uk>
|
||||
Sugu Sougoumarane <ssougou@gmail.com>
|
||||
Sven Almgren <sven@tras.se>
|
||||
Szabolcs Nagy <nsz@port70.net>
|
||||
Tad Glines <tad.glines@gmail.com>
|
||||
Taj Khattra <taj.khattra@gmail.com>
|
||||
Tarmigan Casebolt <tarmigan@gmail.com>
|
||||
Taru Karttunen <taruti@taruti.net>
|
||||
Tetsuo Kiso <tetsuokiso9@gmail.com>
|
||||
Thiago Fransosi Farina <thiago.farina@gmail.com> <tfarina@chromium.org>
|
||||
Thomas Alan Copeland <talan.copeland@gmail.com>
|
||||
Thomas Habets <habets@google.com>
|
||||
Thomas Kappler <tkappler@gmail.com>
|
||||
Timo Savola <timo.savola@gmail.com>
|
||||
Timo Truyts <alkaloid.btx@gmail.com>
|
||||
Tobias Columbus <tobias.columbus@gmail.com> <tobias.columbus@googlemail.com>
|
||||
Todd Wang <toddwang@gmail.com>
|
||||
Tom Linford <tomlinford@gmail.com>
|
||||
Tom Szymanski <tgs@google.com>
|
||||
Tor Andersson <tor.andersson@gmail.com>
|
||||
Travis Cline <travis.cline@gmail.com>
|
||||
Trevor Strohman <trevor.strohman@gmail.com>
|
||||
Tudor Golubenco <tudor.g@gmail.com>
|
||||
Tw <tw19881113@gmail.com>
|
||||
Tyler Bunnell <tylerbunnell@gmail.com>
|
||||
Ugorji Nwoke <ugorji@gmail.com>
|
||||
Ulf Holm Nielsen <doktor@dyregod.dk>
|
||||
Uriel Mangado <uriel@berlinblue.org>
|
||||
Vadim Vygonets <unixdj@gmail.com>
|
||||
Vega Garcia Luis Alfonso <vegacom@gmail.com>
|
||||
Vincent Ambo <tazjin@googlemail.com>
|
||||
Vincent Vanackere <vincent.vanackere@gmail.com>
|
||||
Vinu Rajashekhar <vinutheraj@gmail.com>
|
||||
Vish Subramanian <vish@google.com>
|
||||
Vladimir Nikishenko <vova616@gmail.com>
|
||||
Volker Dobler <dr.volker.dobler@gmail.com>
|
||||
Wei Guangjing <vcc.163@gmail.com>
|
||||
Will Norris <willnorris@google.com>
|
||||
Willem van der Schyff <willemvds@gmail.com>
|
||||
William Chan <willchan@chromium.org>
|
||||
William Josephson <wjosephson@gmail.com>
|
||||
William Orr <will@worrbase.com> <ay1244@gmail.com>
|
||||
Xia Bin <snyh@snyh.org>
|
||||
Xing Xing <mikespook@gmail.com>
|
||||
Yan Zou <yzou@google.com>
|
||||
Yasuhiro Matsumoto <mattn.jp@gmail.com>
|
||||
Yissakhar Z. Beck <yissakhar.beck@gmail.com>
|
||||
Yongjian Xu <i3dmaster@gmail.com>
|
||||
Yoshiyuki Kanno <nekotaroh@gmail.com> <yoshiyuki.kanno@stoic.co.jp>
|
||||
Yusuke Kagiwada <block.rxckin.beats@gmail.com>
|
||||
Yuusei Kuwana <kuwana@kumama.org>
|
||||
Yuval Pavel Zholkover <paulzhol@gmail.com>
|
||||
Yves Junqueira <yves.junqueira@gmail.com>
|
||||
Ziad Hatahet <hatahet@gmail.com>
|
||||
Zorion Arrizabalaga <zorionk@gmail.com>
|
||||
申习之 <bronze1man@gmail.com>
|
||||
|
||||
2
LICENSE
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2012 The Go Authors. All rights reserved.
|
||||
Copyright (c) 2009 The Go Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
|
||||
7
README
@@ -1,12 +1,11 @@
|
||||
This is the source code repository for the Go programming language.
|
||||
|
||||
For documentation about how to install and use Go,
|
||||
visit http://golang.org/ or load doc/install-source.html
|
||||
in your web browser.
|
||||
visit http://golang.org/ or load doc/install.html in your web browser.
|
||||
|
||||
After installing Go, you can view a nicely formatted
|
||||
doc/install-source.html by running godoc --http=:6060
|
||||
and then visiting http://localhost:6060/doc/install/source.
|
||||
doc/install.html by running godoc --http=:6060
|
||||
and then visiting http://localhost:6060/doc/install.html.
|
||||
|
||||
Unless otherwise noted, the Go source files are distributed
|
||||
under the BSD-style license found in the LICENSE file.
|
||||
|
||||
14
api/README
@@ -1,14 +0,0 @@
|
||||
Files in this directory are data for Go's API checker ("go tool api", in src/cmd/api).
|
||||
|
||||
Each file is a list of of API features, one per line.
|
||||
|
||||
go1.txt (and similarly named files) are frozen once a version has been
|
||||
shipped. Each file adds new lines but does not remove any.
|
||||
|
||||
except.txt lists features that may disappear without breaking true
|
||||
compatibility.
|
||||
|
||||
next.txt is the only file intended to be mutated. It's a list of
|
||||
features that may be added to the next version. It only affects
|
||||
warning output from the go api tool.
|
||||
|
||||
330
api/except.txt
@@ -1,330 +0,0 @@
|
||||
pkg net, func ListenUnixgram(string, *UnixAddr) (*UDPConn, error)
|
||||
pkg syscall (darwin-386), func Fchflags(string, int) error
|
||||
pkg syscall (darwin-386-cgo), func Fchflags(string, int) error
|
||||
pkg syscall (darwin-amd64), func Fchflags(string, int) error
|
||||
pkg syscall (darwin-amd64-cgo), func Fchflags(string, int) error
|
||||
pkg syscall (freebsd-386), func Fchflags(string, int) error
|
||||
pkg syscall (freebsd-amd64), func Fchflags(string, int) error
|
||||
pkg syscall (freebsd-arm), func Fchflags(string, int) error
|
||||
pkg syscall (freebsd-arm-cgo), func Fchflags(string, int) error
|
||||
pkg syscall (netbsd-arm), func Fchflags(string, int) error
|
||||
pkg syscall (netbsd-arm-cgo), func Fchflags(string, int) error
|
||||
pkg testing, func RegisterCover(Cover)
|
||||
pkg text/template/parse, type DotNode bool
|
||||
pkg text/template/parse, type Node interface { Copy, String, Type }
|
||||
pkg os (linux-arm), const O_SYNC = 4096
|
||||
pkg os (linux-arm-cgo), const O_SYNC = 4096
|
||||
pkg syscall (darwin-386), const ImplementsGetwd = false
|
||||
pkg syscall (darwin-386-cgo), const ImplementsGetwd = false
|
||||
pkg syscall (darwin-amd64), const ImplementsGetwd = false
|
||||
pkg syscall (darwin-amd64-cgo), const ImplementsGetwd = false
|
||||
pkg syscall (openbsd-386), const BIOCGRTIMEOUT = 1074283118
|
||||
pkg syscall (openbsd-386), const BIOCSRTIMEOUT = 2148024941
|
||||
pkg syscall (openbsd-386), const RTF_FMASK = 63496
|
||||
pkg syscall (openbsd-386), const RTM_VERSION = 4
|
||||
pkg syscall (openbsd-386), const SIOCBRDGDADDR = 2150132039
|
||||
pkg syscall (openbsd-386), const SIOCBRDGGPARAM = 3224922456
|
||||
pkg syscall (openbsd-386), const SIOCBRDGSADDR = 3223873860
|
||||
pkg syscall (openbsd-386), const SYS_CLOCK_GETRES = 234
|
||||
pkg syscall (openbsd-386), const SYS_CLOCK_GETTIME = 232
|
||||
pkg syscall (openbsd-386), const SYS_CLOCK_SETTIME = 233
|
||||
pkg syscall (openbsd-386), const SYS_FHSTATFS = 309
|
||||
pkg syscall (openbsd-386), const SYS_FSTAT = 292
|
||||
pkg syscall (openbsd-386), const SYS_FSTATAT = 316
|
||||
pkg syscall (openbsd-386), const SYS_FSTATFS = 308
|
||||
pkg syscall (openbsd-386), const SYS_FUTIMENS = 327
|
||||
pkg syscall (openbsd-386), const SYS_FUTIMES = 206
|
||||
pkg syscall (openbsd-386), const SYS_GETDIRENTRIES = 312
|
||||
pkg syscall (openbsd-386), const SYS_GETDIRENTRIES ideal-int
|
||||
pkg syscall (openbsd-386), const SYS_GETFSSTAT = 306
|
||||
pkg syscall (openbsd-386), const SYS_GETITIMER = 86
|
||||
pkg syscall (openbsd-386), const SYS_GETRUSAGE = 117
|
||||
pkg syscall (openbsd-386), const SYS_GETTIMEOFDAY = 116
|
||||
pkg syscall (openbsd-386), const SYS_KEVENT = 270
|
||||
pkg syscall (openbsd-386), const SYS_LSTAT = 293
|
||||
pkg syscall (openbsd-386), const SYS_NANOSLEEP = 240
|
||||
pkg syscall (openbsd-386), const SYS_SELECT = 93
|
||||
pkg syscall (openbsd-386), const SYS_SETITIMER = 83
|
||||
pkg syscall (openbsd-386), const SYS_SETTIMEOFDAY = 122
|
||||
pkg syscall (openbsd-386), const SYS_STAT = 291
|
||||
pkg syscall (openbsd-386), const SYS_STATFS = 307
|
||||
pkg syscall (openbsd-386), const SYS_UTIMENSAT = 326
|
||||
pkg syscall (openbsd-386), const SYS_UTIMES = 138
|
||||
pkg syscall (openbsd-386), const SYS_WAIT4 = 7
|
||||
pkg syscall (openbsd-386), const SYS___THRSLEEP = 300
|
||||
pkg syscall (openbsd-386), const SizeofIfData = 208
|
||||
pkg syscall (openbsd-386), const SizeofIfMsghdr = 232
|
||||
pkg syscall (openbsd-386), const SizeofRtMetrics = 48
|
||||
pkg syscall (openbsd-386), const SizeofRtMsghdr = 88
|
||||
pkg syscall (openbsd-386), const TIOCGTSTAMP = 1074295899
|
||||
pkg syscall (openbsd-386), type Dirent struct, Fileno uint32
|
||||
pkg syscall (openbsd-386), type FdSet struct, Bits [32]int32
|
||||
pkg syscall (openbsd-386), type Kevent_t struct, Data int32
|
||||
pkg syscall (openbsd-386), type Mclpool struct, Grown uint32
|
||||
pkg syscall (openbsd-386), type RtMetrics struct, Expire uint32
|
||||
pkg syscall (openbsd-386), type Stat_t struct, Ino uint32
|
||||
pkg syscall (openbsd-386), type Stat_t struct, Lspare0 int32
|
||||
pkg syscall (openbsd-386), type Stat_t struct, Lspare1 int32
|
||||
pkg syscall (openbsd-386), type Stat_t struct, Qspare [2]int64
|
||||
pkg syscall (openbsd-386), type Statfs_t struct, F_ctime uint32
|
||||
pkg syscall (openbsd-386), type Statfs_t struct, F_spare [3]uint32
|
||||
pkg syscall (openbsd-386), type Timespec struct, Sec int32
|
||||
pkg syscall (openbsd-386), type Timeval struct, Sec int32
|
||||
pkg syscall (openbsd-386-cgo), const BIOCGRTIMEOUT = 1074283118
|
||||
pkg syscall (openbsd-386-cgo), const BIOCSRTIMEOUT = 2148024941
|
||||
pkg syscall (openbsd-386-cgo), const RTF_FMASK = 63496
|
||||
pkg syscall (openbsd-386-cgo), const RTM_VERSION = 4
|
||||
pkg syscall (openbsd-386-cgo), const SIOCBRDGDADDR = 2150132039
|
||||
pkg syscall (openbsd-386-cgo), const SIOCBRDGGPARAM = 3224922456
|
||||
pkg syscall (openbsd-386-cgo), const SIOCBRDGSADDR = 3223873860
|
||||
pkg syscall (openbsd-386-cgo), const SYS_CLOCK_GETRES = 234
|
||||
pkg syscall (openbsd-386-cgo), const SYS_CLOCK_GETTIME = 232
|
||||
pkg syscall (openbsd-386-cgo), const SYS_CLOCK_SETTIME = 233
|
||||
pkg syscall (openbsd-386-cgo), const SYS_FHSTATFS = 309
|
||||
pkg syscall (openbsd-386-cgo), const SYS_FSTAT = 292
|
||||
pkg syscall (openbsd-386-cgo), const SYS_FSTATAT = 316
|
||||
pkg syscall (openbsd-386-cgo), const SYS_FSTATFS = 308
|
||||
pkg syscall (openbsd-386-cgo), const SYS_FUTIMENS = 327
|
||||
pkg syscall (openbsd-386-cgo), const SYS_FUTIMES = 206
|
||||
pkg syscall (openbsd-386-cgo), const SYS_GETDIRENTRIES = 312
|
||||
pkg syscall (openbsd-386-cgo), const SYS_GETDIRENTRIES ideal-int
|
||||
pkg syscall (openbsd-386-cgo), const SYS_GETFSSTAT = 306
|
||||
pkg syscall (openbsd-386-cgo), const SYS_GETITIMER = 86
|
||||
pkg syscall (openbsd-386-cgo), const SYS_GETRUSAGE = 117
|
||||
pkg syscall (openbsd-386-cgo), const SYS_GETTIMEOFDAY = 116
|
||||
pkg syscall (openbsd-386-cgo), const SYS_KEVENT = 270
|
||||
pkg syscall (openbsd-386-cgo), const SYS_LSTAT = 293
|
||||
pkg syscall (openbsd-386-cgo), const SYS_NANOSLEEP = 240
|
||||
pkg syscall (openbsd-386-cgo), const SYS_SELECT = 93
|
||||
pkg syscall (openbsd-386-cgo), const SYS_SETITIMER = 83
|
||||
pkg syscall (openbsd-386-cgo), const SYS_SETTIMEOFDAY = 122
|
||||
pkg syscall (openbsd-386-cgo), const SYS_STAT = 291
|
||||
pkg syscall (openbsd-386-cgo), const SYS_STATFS = 307
|
||||
pkg syscall (openbsd-386-cgo), const SYS_UTIMENSAT = 326
|
||||
pkg syscall (openbsd-386-cgo), const SYS_UTIMES = 138
|
||||
pkg syscall (openbsd-386-cgo), const SYS_WAIT4 = 7
|
||||
pkg syscall (openbsd-386-cgo), const SYS___THRSLEEP = 300
|
||||
pkg syscall (openbsd-386-cgo), const SizeofIfData = 208
|
||||
pkg syscall (openbsd-386-cgo), const SizeofIfMsghdr = 232
|
||||
pkg syscall (openbsd-386-cgo), const SizeofRtMetrics = 48
|
||||
pkg syscall (openbsd-386-cgo), const SizeofRtMsghdr = 88
|
||||
pkg syscall (openbsd-386-cgo), const TIOCGTSTAMP = 1074295899
|
||||
pkg syscall (openbsd-386-cgo), type Dirent struct, Fileno uint32
|
||||
pkg syscall (openbsd-386-cgo), type FdSet struct, Bits [32]int32
|
||||
pkg syscall (openbsd-386-cgo), type Kevent_t struct, Data int32
|
||||
pkg syscall (openbsd-386-cgo), type Mclpool struct, Grown uint32
|
||||
pkg syscall (openbsd-386-cgo), type RtMetrics struct, Expire uint32
|
||||
pkg syscall (openbsd-386-cgo), type Stat_t struct, Ino uint32
|
||||
pkg syscall (openbsd-386-cgo), type Stat_t struct, Lspare0 int32
|
||||
pkg syscall (openbsd-386-cgo), type Stat_t struct, Lspare1 int32
|
||||
pkg syscall (openbsd-386-cgo), type Stat_t struct, Qspare [2]int64
|
||||
pkg syscall (openbsd-386-cgo), type Statfs_t struct, F_ctime uint32
|
||||
pkg syscall (openbsd-386-cgo), type Statfs_t struct, F_spare [3]uint32
|
||||
pkg syscall (openbsd-386-cgo), type Timespec struct, Sec int32
|
||||
pkg syscall (openbsd-386-cgo), type Timeval struct, Sec int32
|
||||
pkg syscall (openbsd-amd64), const CCR0_FLUSH = 16
|
||||
pkg syscall (openbsd-amd64), const CCR0_FLUSH ideal-int
|
||||
pkg syscall (openbsd-amd64), const CPUID_CFLUSH = 524288
|
||||
pkg syscall (openbsd-amd64), const CPUID_CFLUSH ideal-int
|
||||
pkg syscall (openbsd-amd64), const EFER_LMA = 1024
|
||||
pkg syscall (openbsd-amd64), const EFER_LMA ideal-int
|
||||
pkg syscall (openbsd-amd64), const EFER_LME = 256
|
||||
pkg syscall (openbsd-amd64), const EFER_LME ideal-int
|
||||
pkg syscall (openbsd-amd64), const EFER_NXE = 2048
|
||||
pkg syscall (openbsd-amd64), const EFER_NXE ideal-int
|
||||
pkg syscall (openbsd-amd64), const EFER_SCE = 1
|
||||
pkg syscall (openbsd-amd64), const EFER_SCE ideal-int
|
||||
pkg syscall (openbsd-amd64), const PMC5_PIPELINE_FLUSH = 21
|
||||
pkg syscall (openbsd-amd64), const PMC5_PIPELINE_FLUSH ideal-int
|
||||
pkg syscall (openbsd-amd64), const RTF_FMASK = 63496
|
||||
pkg syscall (openbsd-amd64), const RTM_VERSION = 4
|
||||
pkg syscall (openbsd-amd64), const SIOCBRDGDADDR = 2150132039
|
||||
pkg syscall (openbsd-amd64), const SIOCBRDGSADDR = 3223873860
|
||||
pkg syscall (openbsd-amd64), const SYS_CLOCK_GETRES = 234
|
||||
pkg syscall (openbsd-amd64), const SYS_CLOCK_GETTIME = 232
|
||||
pkg syscall (openbsd-amd64), const SYS_CLOCK_SETTIME = 233
|
||||
pkg syscall (openbsd-amd64), const SYS_FHSTATFS = 309
|
||||
pkg syscall (openbsd-amd64), const SYS_FSTAT = 292
|
||||
pkg syscall (openbsd-amd64), const SYS_FSTATAT = 316
|
||||
pkg syscall (openbsd-amd64), const SYS_FSTATFS = 308
|
||||
pkg syscall (openbsd-amd64), const SYS_FUTIMENS = 327
|
||||
pkg syscall (openbsd-amd64), const SYS_FUTIMES = 206
|
||||
pkg syscall (openbsd-amd64), const SYS_GETDIRENTRIES = 312
|
||||
pkg syscall (openbsd-amd64), const SYS_GETDIRENTRIES ideal-int
|
||||
pkg syscall (openbsd-amd64), const SYS_GETFSSTAT = 306
|
||||
pkg syscall (openbsd-amd64), const SYS_GETITIMER = 86
|
||||
pkg syscall (openbsd-amd64), const SYS_GETRUSAGE = 117
|
||||
pkg syscall (openbsd-amd64), const SYS_GETTIMEOFDAY = 116
|
||||
pkg syscall (openbsd-amd64), const SYS_KEVENT = 270
|
||||
pkg syscall (openbsd-amd64), const SYS_LSTAT = 293
|
||||
pkg syscall (openbsd-amd64), const SYS_NANOSLEEP = 240
|
||||
pkg syscall (openbsd-amd64), const SYS_SELECT = 93
|
||||
pkg syscall (openbsd-amd64), const SYS_SETITIMER = 83
|
||||
pkg syscall (openbsd-amd64), const SYS_SETTIMEOFDAY = 122
|
||||
pkg syscall (openbsd-amd64), const SYS_STAT = 291
|
||||
pkg syscall (openbsd-amd64), const SYS_STATFS = 307
|
||||
pkg syscall (openbsd-amd64), const SYS_UTIMENSAT = 326
|
||||
pkg syscall (openbsd-amd64), const SYS_UTIMES = 138
|
||||
pkg syscall (openbsd-amd64), const SYS_WAIT4 = 7
|
||||
pkg syscall (openbsd-amd64), const SYS___THRSLEEP = 300
|
||||
pkg syscall (openbsd-amd64), const SizeofRtMetrics = 48
|
||||
pkg syscall (openbsd-amd64), const SizeofRtMsghdr = 88
|
||||
pkg syscall (openbsd-amd64), type Dirent struct, Fileno uint32
|
||||
pkg syscall (openbsd-amd64), type FdSet struct, Bits [32]int32
|
||||
pkg syscall (openbsd-amd64), type Kevent_t struct, Data int32
|
||||
pkg syscall (openbsd-amd64), type Kevent_t struct, Ident uint32
|
||||
pkg syscall (openbsd-amd64), type Mclpool struct, Grown uint32
|
||||
pkg syscall (openbsd-amd64), type RtMetrics struct, Expire uint32
|
||||
pkg syscall (openbsd-amd64), type Stat_t struct, Ino uint32
|
||||
pkg syscall (openbsd-amd64), type Stat_t struct, Lspare0 int32
|
||||
pkg syscall (openbsd-amd64), type Stat_t struct, Lspare1 int32
|
||||
pkg syscall (openbsd-amd64), type Stat_t struct, Qspare [2]int64
|
||||
pkg syscall (openbsd-amd64), type Statfs_t struct, F_ctime uint32
|
||||
pkg syscall (openbsd-amd64), type Statfs_t struct, F_spare [3]uint32
|
||||
pkg syscall (openbsd-amd64), type Statfs_t struct, Pad_cgo_1 [4]uint8
|
||||
pkg syscall (openbsd-amd64), type Timespec struct, Pad_cgo_0 [4]uint8
|
||||
pkg syscall (openbsd-amd64), type Timespec struct, Sec int32
|
||||
pkg syscall (openbsd-amd64-cgo), const CCR0_FLUSH = 16
|
||||
pkg syscall (openbsd-amd64-cgo), const CCR0_FLUSH ideal-int
|
||||
pkg syscall (openbsd-amd64-cgo), const CPUID_CFLUSH = 524288
|
||||
pkg syscall (openbsd-amd64-cgo), const CPUID_CFLUSH ideal-int
|
||||
pkg syscall (openbsd-amd64-cgo), const EFER_LMA = 1024
|
||||
pkg syscall (openbsd-amd64-cgo), const EFER_LMA ideal-int
|
||||
pkg syscall (openbsd-amd64-cgo), const EFER_LME = 256
|
||||
pkg syscall (openbsd-amd64-cgo), const EFER_LME ideal-int
|
||||
pkg syscall (openbsd-amd64-cgo), const EFER_NXE = 2048
|
||||
pkg syscall (openbsd-amd64-cgo), const EFER_NXE ideal-int
|
||||
pkg syscall (openbsd-amd64-cgo), const EFER_SCE = 1
|
||||
pkg syscall (openbsd-amd64-cgo), const EFER_SCE ideal-int
|
||||
pkg syscall (openbsd-amd64-cgo), const PMC5_PIPELINE_FLUSH = 21
|
||||
pkg syscall (openbsd-amd64-cgo), const PMC5_PIPELINE_FLUSH ideal-int
|
||||
pkg syscall (openbsd-amd64-cgo), const RTF_FMASK = 63496
|
||||
pkg syscall (openbsd-amd64-cgo), const RTM_VERSION = 4
|
||||
pkg syscall (openbsd-amd64-cgo), const SIOCBRDGDADDR = 2150132039
|
||||
pkg syscall (openbsd-amd64-cgo), const SIOCBRDGSADDR = 3223873860
|
||||
pkg syscall (openbsd-amd64-cgo), const SYS_CLOCK_GETRES = 234
|
||||
pkg syscall (openbsd-amd64-cgo), const SYS_CLOCK_GETTIME = 232
|
||||
pkg syscall (openbsd-amd64-cgo), const SYS_CLOCK_SETTIME = 233
|
||||
pkg syscall (openbsd-amd64-cgo), const SYS_FHSTATFS = 309
|
||||
pkg syscall (openbsd-amd64-cgo), const SYS_FSTAT = 292
|
||||
pkg syscall (openbsd-amd64-cgo), const SYS_FSTATAT = 316
|
||||
pkg syscall (openbsd-amd64-cgo), const SYS_FSTATFS = 308
|
||||
pkg syscall (openbsd-amd64-cgo), const SYS_FUTIMENS = 327
|
||||
pkg syscall (openbsd-amd64-cgo), const SYS_FUTIMES = 206
|
||||
pkg syscall (openbsd-amd64-cgo), const SYS_GETDIRENTRIES = 312
|
||||
pkg syscall (openbsd-amd64-cgo), const SYS_GETDIRENTRIES ideal-int
|
||||
pkg syscall (openbsd-amd64-cgo), const SYS_GETFSSTAT = 306
|
||||
pkg syscall (openbsd-amd64-cgo), const SYS_GETITIMER = 86
|
||||
pkg syscall (openbsd-amd64-cgo), const SYS_GETRUSAGE = 117
|
||||
pkg syscall (openbsd-amd64-cgo), const SYS_GETTIMEOFDAY = 116
|
||||
pkg syscall (openbsd-amd64-cgo), const SYS_KEVENT = 270
|
||||
pkg syscall (openbsd-amd64-cgo), const SYS_LSTAT = 293
|
||||
pkg syscall (openbsd-amd64-cgo), const SYS_NANOSLEEP = 240
|
||||
pkg syscall (openbsd-amd64-cgo), const SYS_SELECT = 93
|
||||
pkg syscall (openbsd-amd64-cgo), const SYS_SETITIMER = 83
|
||||
pkg syscall (openbsd-amd64-cgo), const SYS_SETTIMEOFDAY = 122
|
||||
pkg syscall (openbsd-amd64-cgo), const SYS_STAT = 291
|
||||
pkg syscall (openbsd-amd64-cgo), const SYS_STATFS = 307
|
||||
pkg syscall (openbsd-amd64-cgo), const SYS_UTIMENSAT = 326
|
||||
pkg syscall (openbsd-amd64-cgo), const SYS_UTIMES = 138
|
||||
pkg syscall (openbsd-amd64-cgo), const SYS_WAIT4 = 7
|
||||
pkg syscall (openbsd-amd64-cgo), const SYS___THRSLEEP = 300
|
||||
pkg syscall (openbsd-amd64-cgo), const SizeofRtMetrics = 48
|
||||
pkg syscall (openbsd-amd64-cgo), const SizeofRtMsghdr = 88
|
||||
pkg syscall (openbsd-amd64-cgo), type Dirent struct, Fileno uint32
|
||||
pkg syscall (openbsd-amd64-cgo), type FdSet struct, Bits [32]int32
|
||||
pkg syscall (openbsd-amd64-cgo), type Kevent_t struct, Data int32
|
||||
pkg syscall (openbsd-amd64-cgo), type Kevent_t struct, Ident uint32
|
||||
pkg syscall (openbsd-amd64-cgo), type Mclpool struct, Grown uint32
|
||||
pkg syscall (openbsd-amd64-cgo), type RtMetrics struct, Expire uint32
|
||||
pkg syscall (openbsd-amd64-cgo), type Stat_t struct, Ino uint32
|
||||
pkg syscall (openbsd-amd64-cgo), type Stat_t struct, Lspare0 int32
|
||||
pkg syscall (openbsd-amd64-cgo), type Stat_t struct, Lspare1 int32
|
||||
pkg syscall (openbsd-amd64-cgo), type Stat_t struct, Qspare [2]int64
|
||||
pkg syscall (openbsd-amd64-cgo), type Statfs_t struct, F_ctime uint32
|
||||
pkg syscall (openbsd-amd64-cgo), type Statfs_t struct, F_spare [3]uint32
|
||||
pkg syscall (openbsd-amd64-cgo), type Statfs_t struct, Pad_cgo_1 [4]uint8
|
||||
pkg syscall (openbsd-amd64-cgo), type Timespec struct, Pad_cgo_0 [4]uint8
|
||||
pkg syscall (openbsd-amd64-cgo), type Timespec struct, Sec int32
|
||||
pkg unicode, const Version = "6.2.0"
|
||||
pkg syscall (freebsd-386), const AF_MAX = 38
|
||||
pkg syscall (freebsd-386), const DLT_MATCHING_MAX = 242
|
||||
pkg syscall (freebsd-386), const ELAST = 94
|
||||
pkg syscall (freebsd-386), const O_CLOEXEC = 0
|
||||
pkg syscall (freebsd-386-cgo), const AF_MAX = 38
|
||||
pkg syscall (freebsd-386-cgo), const DLT_MATCHING_MAX = 242
|
||||
pkg syscall (freebsd-386-cgo), const ELAST = 94
|
||||
pkg syscall (freebsd-386-cgo), const O_CLOEXEC = 0
|
||||
pkg syscall (freebsd-amd64), const AF_MAX = 38
|
||||
pkg syscall (freebsd-amd64), const DLT_MATCHING_MAX = 242
|
||||
pkg syscall (freebsd-amd64), const ELAST = 94
|
||||
pkg syscall (freebsd-amd64), const O_CLOEXEC = 0
|
||||
pkg syscall (freebsd-amd64-cgo), const AF_MAX = 38
|
||||
pkg syscall (freebsd-amd64-cgo), const DLT_MATCHING_MAX = 242
|
||||
pkg syscall (freebsd-amd64-cgo), const ELAST = 94
|
||||
pkg syscall (freebsd-amd64-cgo), const O_CLOEXEC = 0
|
||||
pkg syscall (freebsd-arm), const AF_MAX = 38
|
||||
pkg syscall (freebsd-arm), const BIOCGRTIMEOUT = 1074545262
|
||||
pkg syscall (freebsd-arm), const BIOCSRTIMEOUT = 2148287085
|
||||
pkg syscall (freebsd-arm), const ELAST = 94
|
||||
pkg syscall (freebsd-arm), const O_CLOEXEC = 0
|
||||
pkg syscall (freebsd-arm), const SIOCAIFADDR = 2151967019
|
||||
pkg syscall (freebsd-arm), const SIOCGIFSTATUS = 3274991931
|
||||
pkg syscall (freebsd-arm), const SIOCSIFPHYADDR = 2151967046
|
||||
pkg syscall (freebsd-arm), const SYS_CAP_FCNTLS_GET = 537
|
||||
pkg syscall (freebsd-arm), const SYS_CAP_FCNTLS_GET ideal-int
|
||||
pkg syscall (freebsd-arm), const SYS_CAP_FCNTLS_LIMIT = 536
|
||||
pkg syscall (freebsd-arm), const SYS_CAP_FCNTLS_LIMIT ideal-int
|
||||
pkg syscall (freebsd-arm), const SYS_CAP_IOCTLS_GET = 535
|
||||
pkg syscall (freebsd-arm), const SYS_CAP_IOCTLS_GET ideal-int
|
||||
pkg syscall (freebsd-arm), const SYS_CAP_IOCTLS_LIMIT = 534
|
||||
pkg syscall (freebsd-arm), const SYS_CAP_IOCTLS_LIMIT ideal-int
|
||||
pkg syscall (freebsd-arm), const SYS_CAP_RIGHTS_GET = 515
|
||||
pkg syscall (freebsd-arm), const SYS_CAP_RIGHTS_GET ideal-int
|
||||
pkg syscall (freebsd-arm), const SYS_CAP_RIGHTS_LIMIT = 533
|
||||
pkg syscall (freebsd-arm), const SYS_CAP_RIGHTS_LIMIT ideal-int
|
||||
pkg syscall (freebsd-arm), const SizeofBpfHdr = 24
|
||||
pkg syscall (freebsd-arm), const SizeofIfData = 88
|
||||
pkg syscall (freebsd-arm), const SizeofIfMsghdr = 104
|
||||
pkg syscall (freebsd-arm), const SizeofSockaddrDatalink = 56
|
||||
pkg syscall (freebsd-arm), const SizeofSockaddrUnix = 108
|
||||
pkg syscall (freebsd-arm), const TIOCTIMESTAMP = 1074558041
|
||||
pkg syscall (freebsd-arm), type BpfHdr struct, Pad_cgo_0 [2]uint8
|
||||
pkg syscall (freebsd-arm), type RawSockaddrDatalink struct, Pad_cgo_0 [2]uint8
|
||||
pkg syscall (freebsd-arm), type RawSockaddrUnix struct, Pad_cgo_0 [2]uint8
|
||||
pkg syscall (freebsd-arm), type Stat_t struct, Pad_cgo_0 [4]uint8
|
||||
pkg syscall (freebsd-arm-cgo), const AF_MAX = 38
|
||||
pkg syscall (freebsd-arm-cgo), const BIOCGRTIMEOUT = 1074545262
|
||||
pkg syscall (freebsd-arm-cgo), const BIOCSRTIMEOUT = 2148287085
|
||||
pkg syscall (freebsd-arm-cgo), const ELAST = 94
|
||||
pkg syscall (freebsd-arm-cgo), const O_CLOEXEC = 0
|
||||
pkg syscall (freebsd-arm-cgo), const SIOCAIFADDR = 2151967019
|
||||
pkg syscall (freebsd-arm-cgo), const SIOCGIFSTATUS = 3274991931
|
||||
pkg syscall (freebsd-arm-cgo), const SIOCSIFPHYADDR = 2151967046
|
||||
pkg syscall (freebsd-arm-cgo), const SYS_CAP_FCNTLS_GET = 537
|
||||
pkg syscall (freebsd-arm-cgo), const SYS_CAP_FCNTLS_GET ideal-int
|
||||
pkg syscall (freebsd-arm-cgo), const SYS_CAP_FCNTLS_LIMIT = 536
|
||||
pkg syscall (freebsd-arm-cgo), const SYS_CAP_FCNTLS_LIMIT ideal-int
|
||||
pkg syscall (freebsd-arm-cgo), const SYS_CAP_IOCTLS_GET = 535
|
||||
pkg syscall (freebsd-arm-cgo), const SYS_CAP_IOCTLS_GET ideal-int
|
||||
pkg syscall (freebsd-arm-cgo), const SYS_CAP_IOCTLS_LIMIT = 534
|
||||
pkg syscall (freebsd-arm-cgo), const SYS_CAP_IOCTLS_LIMIT ideal-int
|
||||
pkg syscall (freebsd-arm-cgo), const SYS_CAP_RIGHTS_GET = 515
|
||||
pkg syscall (freebsd-arm-cgo), const SYS_CAP_RIGHTS_GET ideal-int
|
||||
pkg syscall (freebsd-arm-cgo), const SYS_CAP_RIGHTS_LIMIT = 533
|
||||
pkg syscall (freebsd-arm-cgo), const SYS_CAP_RIGHTS_LIMIT ideal-int
|
||||
pkg syscall (freebsd-arm-cgo), const SizeofBpfHdr = 24
|
||||
pkg syscall (freebsd-arm-cgo), const SizeofIfData = 88
|
||||
pkg syscall (freebsd-arm-cgo), const SizeofIfMsghdr = 104
|
||||
pkg syscall (freebsd-arm-cgo), const SizeofSockaddrDatalink = 56
|
||||
pkg syscall (freebsd-arm-cgo), const SizeofSockaddrUnix = 108
|
||||
pkg syscall (freebsd-arm-cgo), const TIOCTIMESTAMP = 1074558041
|
||||
pkg syscall (freebsd-arm-cgo), type BpfHdr struct, Pad_cgo_0 [2]uint8
|
||||
pkg syscall (freebsd-arm-cgo), type RawSockaddrDatalink struct, Pad_cgo_0 [2]uint8
|
||||
pkg syscall (freebsd-arm-cgo), type RawSockaddrUnix struct, Pad_cgo_0 [2]uint8
|
||||
pkg syscall (freebsd-arm-cgo), type Stat_t struct, Pad_cgo_0 [4]uint8
|
||||
pkg syscall (netbsd-arm), const SizeofIfData = 132
|
||||
pkg syscall (netbsd-arm), type IfMsghdr struct, Pad_cgo_1 [4]uint8
|
||||
pkg syscall (netbsd-arm-cgo), const SizeofIfData = 132
|
||||
pkg syscall (netbsd-arm-cgo), type IfMsghdr struct, Pad_cgo_1 [4]uint8
|
||||
pkg unicode, const Version = "6.3.0"
|
||||
50427
api/go1.1.txt
32484
api/go1.2.txt
2053
api/go1.3.txt
30871
api/go1.txt
141
api/next.txt
@@ -1,141 +0,0 @@
|
||||
pkg debug/goobj, const SBSS = 21
|
||||
pkg debug/goobj, const SBSS SymKind
|
||||
pkg debug/goobj, const SCONST = 31
|
||||
pkg debug/goobj, const SCONST SymKind
|
||||
pkg debug/goobj, const SDATA = 19
|
||||
pkg debug/goobj, const SDATA SymKind
|
||||
pkg debug/goobj, const SDYNIMPORT = 32
|
||||
pkg debug/goobj, const SDYNIMPORT SymKind
|
||||
pkg debug/goobj, const SELFROSECT = 12
|
||||
pkg debug/goobj, const SELFROSECT SymKind
|
||||
pkg debug/goobj, const SELFRXSECT = 2
|
||||
pkg debug/goobj, const SELFRXSECT SymKind
|
||||
pkg debug/goobj, const SELFSECT = 14
|
||||
pkg debug/goobj, const SELFSECT SymKind
|
||||
pkg debug/goobj, const SFILE = 29
|
||||
pkg debug/goobj, const SFILE SymKind
|
||||
pkg debug/goobj, const SFILEPATH = 30
|
||||
pkg debug/goobj, const SFILEPATH SymKind
|
||||
pkg debug/goobj, const SFUNCTAB = 8
|
||||
pkg debug/goobj, const SFUNCTAB SymKind
|
||||
pkg debug/goobj, const SGOFUNC = 6
|
||||
pkg debug/goobj, const SGOFUNC SymKind
|
||||
pkg debug/goobj, const SGOSTRING = 5
|
||||
pkg debug/goobj, const SGOSTRING SymKind
|
||||
pkg debug/goobj, const SHOSTOBJ = 33
|
||||
pkg debug/goobj, const SHOSTOBJ SymKind
|
||||
pkg debug/goobj, const SINITARR = 18
|
||||
pkg debug/goobj, const SINITARR SymKind
|
||||
pkg debug/goobj, const SMACHO = 15
|
||||
pkg debug/goobj, const SMACHO SymKind
|
||||
pkg debug/goobj, const SMACHOGOT = 16
|
||||
pkg debug/goobj, const SMACHOGOT SymKind
|
||||
pkg debug/goobj, const SMACHOINDIRECTGOT = 28
|
||||
pkg debug/goobj, const SMACHOINDIRECTGOT SymKind
|
||||
pkg debug/goobj, const SMACHOINDIRECTPLT = 27
|
||||
pkg debug/goobj, const SMACHOINDIRECTPLT SymKind
|
||||
pkg debug/goobj, const SMACHOPLT = 13
|
||||
pkg debug/goobj, const SMACHOPLT SymKind
|
||||
pkg debug/goobj, const SMACHOSYMSTR = 25
|
||||
pkg debug/goobj, const SMACHOSYMSTR SymKind
|
||||
pkg debug/goobj, const SMACHOSYMTAB = 26
|
||||
pkg debug/goobj, const SMACHOSYMTAB SymKind
|
||||
pkg debug/goobj, const SNOPTRBSS = 22
|
||||
pkg debug/goobj, const SNOPTRBSS SymKind
|
||||
pkg debug/goobj, const SNOPTRDATA = 17
|
||||
pkg debug/goobj, const SNOPTRDATA SymKind
|
||||
pkg debug/goobj, const SPCLNTAB = 11
|
||||
pkg debug/goobj, const SPCLNTAB SymKind
|
||||
pkg debug/goobj, const SRODATA = 7
|
||||
pkg debug/goobj, const SRODATA SymKind
|
||||
pkg debug/goobj, const SSTRING = 4
|
||||
pkg debug/goobj, const SSTRING SymKind
|
||||
pkg debug/goobj, const SSYMTAB = 10
|
||||
pkg debug/goobj, const SSYMTAB SymKind
|
||||
pkg debug/goobj, const STEXT = 1
|
||||
pkg debug/goobj, const STEXT SymKind
|
||||
pkg debug/goobj, const STLSBSS = 23
|
||||
pkg debug/goobj, const STLSBSS SymKind
|
||||
pkg debug/goobj, const STYPE = 3
|
||||
pkg debug/goobj, const STYPE SymKind
|
||||
pkg debug/goobj, const STYPELINK = 9
|
||||
pkg debug/goobj, const STYPELINK SymKind
|
||||
pkg debug/goobj, const SWINDOWS = 20
|
||||
pkg debug/goobj, const SWINDOWS SymKind
|
||||
pkg debug/goobj, const SXREF = 24
|
||||
pkg debug/goobj, const SXREF SymKind
|
||||
pkg debug/goobj, func Parse(io.ReadSeeker, string) (*Package, error)
|
||||
pkg debug/goobj, method (Sym) String() string
|
||||
pkg debug/goobj, method (SymID) String() string
|
||||
pkg debug/goobj, method (SymKind) String() string
|
||||
pkg debug/goobj, type Data struct
|
||||
pkg debug/goobj, type Data struct, Offset int64
|
||||
pkg debug/goobj, type Data struct, Size int64
|
||||
pkg debug/goobj, type Func struct
|
||||
pkg debug/goobj, type Func struct, Args int
|
||||
pkg debug/goobj, type Func struct, File []string
|
||||
pkg debug/goobj, type Func struct, Frame int
|
||||
pkg debug/goobj, type Func struct, FuncData []FuncData
|
||||
pkg debug/goobj, type Func struct, Leaf bool
|
||||
pkg debug/goobj, type Func struct, NoSplit bool
|
||||
pkg debug/goobj, type Func struct, PCData []Data
|
||||
pkg debug/goobj, type Func struct, PCFile Data
|
||||
pkg debug/goobj, type Func struct, PCLine Data
|
||||
pkg debug/goobj, type Func struct, PCSP Data
|
||||
pkg debug/goobj, type Func struct, Var []Var
|
||||
pkg debug/goobj, type FuncData struct
|
||||
pkg debug/goobj, type FuncData struct, Offset int64
|
||||
pkg debug/goobj, type FuncData struct, Sym SymID
|
||||
pkg debug/goobj, type Package struct
|
||||
pkg debug/goobj, type Package struct, ImportPath string
|
||||
pkg debug/goobj, type Package struct, Imports []string
|
||||
pkg debug/goobj, type Package struct, MaxVersion int
|
||||
pkg debug/goobj, type Package struct, Syms []*Sym
|
||||
pkg debug/goobj, type Reloc struct
|
||||
pkg debug/goobj, type Reloc struct, Add int
|
||||
pkg debug/goobj, type Reloc struct, Offset int
|
||||
pkg debug/goobj, type Reloc struct, Size int
|
||||
pkg debug/goobj, type Reloc struct, Sym SymID
|
||||
pkg debug/goobj, type Reloc struct, Type int
|
||||
pkg debug/goobj, type Sym struct
|
||||
pkg debug/goobj, type Sym struct, Data Data
|
||||
pkg debug/goobj, type Sym struct, DupOK bool
|
||||
pkg debug/goobj, type Sym struct, Func *Func
|
||||
pkg debug/goobj, type Sym struct, Kind SymKind
|
||||
pkg debug/goobj, type Sym struct, Reloc []Reloc
|
||||
pkg debug/goobj, type Sym struct, Size int
|
||||
pkg debug/goobj, type Sym struct, Type SymID
|
||||
pkg debug/goobj, type Sym struct, embedded SymID
|
||||
pkg debug/goobj, type SymID struct
|
||||
pkg debug/goobj, type SymID struct, Name string
|
||||
pkg debug/goobj, type SymID struct, Version int
|
||||
pkg debug/goobj, type SymKind int
|
||||
pkg debug/goobj, type Var struct
|
||||
pkg debug/goobj, type Var struct, Kind int
|
||||
pkg debug/goobj, type Var struct, Name string
|
||||
pkg debug/goobj, type Var struct, Offset int
|
||||
pkg debug/goobj, type Var struct, Type SymID
|
||||
pkg unicode, const Version = "7.0.0"
|
||||
pkg unicode, var Bassa_Vah *RangeTable
|
||||
pkg unicode, var Caucasian_Albanian *RangeTable
|
||||
pkg unicode, var Duployan *RangeTable
|
||||
pkg unicode, var Elbasan *RangeTable
|
||||
pkg unicode, var Grantha *RangeTable
|
||||
pkg unicode, var Khojki *RangeTable
|
||||
pkg unicode, var Khudawadi *RangeTable
|
||||
pkg unicode, var Linear_A *RangeTable
|
||||
pkg unicode, var Mahajani *RangeTable
|
||||
pkg unicode, var Manichaean *RangeTable
|
||||
pkg unicode, var Mende_Kikakui *RangeTable
|
||||
pkg unicode, var Modi *RangeTable
|
||||
pkg unicode, var Mro *RangeTable
|
||||
pkg unicode, var Nabataean *RangeTable
|
||||
pkg unicode, var Old_North_Arabian *RangeTable
|
||||
pkg unicode, var Old_Permic *RangeTable
|
||||
pkg unicode, var Pahawh_Hmong *RangeTable
|
||||
pkg unicode, var Palmyrene *RangeTable
|
||||
pkg unicode, var Pau_Cin_Hau *RangeTable
|
||||
pkg unicode, var Psalter_Pahlavi *RangeTable
|
||||
pkg unicode, var Siddham *RangeTable
|
||||
pkg unicode, var Tirhuta *RangeTable
|
||||
pkg unicode, var Warang_Citi *RangeTable
|
||||
BIN
doc/ExpressivenessOfGo.pdf
Normal file
BIN
doc/GoCourseDay1.pdf
Normal file
BIN
doc/GoCourseDay2.pdf
Normal file
BIN
doc/GoCourseDay3.pdf
Normal file
11
doc/Makefile
Normal file
@@ -0,0 +1,11 @@
|
||||
# Copyright 2009 The Go Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style
|
||||
# license that can be found in the LICENSE file.
|
||||
|
||||
include ../src/Make.inc
|
||||
|
||||
TARG=htmlgen
|
||||
GOFILES=\
|
||||
htmlgen.go\
|
||||
|
||||
include ../src/Make.cmd
|
||||
200
doc/all.css
Normal file
@@ -0,0 +1,200 @@
|
||||
/* General Styles */
|
||||
body {
|
||||
font-family: "Bitstream Vera Sans", Verdana, sans-serif;
|
||||
font-size: 81.25%;
|
||||
line-height: 1.23em;
|
||||
padding: 0;
|
||||
margin: 1.23em;
|
||||
background: white;
|
||||
color: black;
|
||||
}
|
||||
a {
|
||||
color: #04a;
|
||||
text-decoration: none;
|
||||
}
|
||||
a:visited {
|
||||
color: #04a;
|
||||
}
|
||||
a:hover {
|
||||
color: #a40;
|
||||
text-decoration: underline;
|
||||
}
|
||||
a:active {
|
||||
color: #c00;
|
||||
}
|
||||
code, pre {
|
||||
font-size: 1.2em;
|
||||
}
|
||||
pre {
|
||||
background: #F0F0F0;
|
||||
padding: 0.5em 1em;
|
||||
}
|
||||
|
||||
/* Top bar */
|
||||
#container {
|
||||
width: 100%;
|
||||
margin: auto;
|
||||
}
|
||||
#topnav {
|
||||
height: 55px;
|
||||
background: url(/doc/logo.png) no-repeat top left;
|
||||
}
|
||||
a#logo-box {
|
||||
display: block;
|
||||
height: 55px;
|
||||
}
|
||||
h1#title {
|
||||
display: none;
|
||||
}
|
||||
#nav-main {
|
||||
float: right;
|
||||
width: 500px;
|
||||
margin-top: -5px;
|
||||
text-align: center;
|
||||
}
|
||||
#nav-main ul {
|
||||
padding-left: 0;
|
||||
margin-left: 0;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
#nav-main li a {
|
||||
display: inline;
|
||||
display: inline-block;
|
||||
padding: .46em .62em .38em .62em;
|
||||
}
|
||||
#nav-main li a:link,
|
||||
#nav-main li a:visited {
|
||||
color: #000;
|
||||
}
|
||||
#nav-main li {
|
||||
display: inline;
|
||||
display: inline-block;
|
||||
background: #e6e6e6 url(/doc/button_background.png) repeat-x;
|
||||
border: solid 1px #999;
|
||||
margin-left: -1px;
|
||||
text-shadow: #fff 0 1px 0;
|
||||
box-shadow: 0 1px 1px #ccc;
|
||||
-moz-box-shadow: 0 1px 1px #ccc;
|
||||
-webkit-box-shadow: 0 1px 1px #ccc;
|
||||
}
|
||||
#nav-main li:first-child {
|
||||
-moz-border-top-left-radius: 4px;
|
||||
border-top-left-radius: 4px;
|
||||
-moz-border-bottom-left-radius: 4px;
|
||||
border-bottom-left-radius: 4px;
|
||||
}
|
||||
#nav-main li:last-child {
|
||||
-moz-border-top-right-radius: 4px;
|
||||
border-top-right-radius: 4px;
|
||||
-moz-border-bottom-right-radius: 4px;
|
||||
border-bottom-right-radius: 4px;
|
||||
}
|
||||
#nav-main .quickref {
|
||||
color: #444;
|
||||
}
|
||||
#nav-main .quickref .sep {
|
||||
color: #999;
|
||||
}
|
||||
#search {
|
||||
width: 120px;
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
#search.inactive {
|
||||
text-align: center;
|
||||
color: #444;
|
||||
}
|
||||
|
||||
/* Footer */
|
||||
#site-info {
|
||||
position: relative;
|
||||
text-align: center;
|
||||
}
|
||||
#site-info, #site-info a:link, #site-info a:visited {
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
/* Content */
|
||||
#content {
|
||||
clear: both;
|
||||
padding: 0;
|
||||
position: relative;
|
||||
margin-top: 1.5em;
|
||||
margin-bottom: 1.5em;
|
||||
border-top: solid 1px #aaa;
|
||||
border-bottom: solid 1px #aaa;
|
||||
}
|
||||
.left-column {
|
||||
width: 49%;
|
||||
float: left;
|
||||
}
|
||||
.right-column {
|
||||
width: 49%;
|
||||
float: right;
|
||||
}
|
||||
.end-columns {
|
||||
clear: both;
|
||||
}
|
||||
#content h1 {
|
||||
margin-bottom: -0em;
|
||||
padding: 0;
|
||||
}
|
||||
#content h2 {
|
||||
border-top: 2px solid #ddd;
|
||||
padding: 8px 5px;
|
||||
margin: 1.5em 0 0;
|
||||
}
|
||||
#content .subtitle {
|
||||
margin-top: 1em;
|
||||
display: block;
|
||||
}
|
||||
.navtop a {
|
||||
font-weight: normal; font-size: 7pt;
|
||||
float: right; color: #999;
|
||||
}
|
||||
|
||||
/* Content and Code Highlighting */
|
||||
pre.ebnf, pre.grammar {
|
||||
background: #FFFFE0;
|
||||
}
|
||||
span.ln {
|
||||
font-size: 80%;
|
||||
color: #777777;
|
||||
}
|
||||
span.comment {
|
||||
color: #002090;
|
||||
}
|
||||
span.highlight {
|
||||
background: #FF9900;
|
||||
font-weight: bold;
|
||||
}
|
||||
span.highlight-comment {
|
||||
background: #FF9900;
|
||||
font-weight: bold;
|
||||
color: #002090;
|
||||
}
|
||||
span.selection {
|
||||
background: #FFFF00
|
||||
}
|
||||
span.selection-comment {
|
||||
color: #002090;
|
||||
background: #FFFF00
|
||||
}
|
||||
span.selection-highlight {
|
||||
background: #FF9900;
|
||||
font-weight: bold;
|
||||
}
|
||||
span.selection-highlight-comment {
|
||||
background: #FF9900;
|
||||
font-weight: bold;
|
||||
color: #002090;
|
||||
}
|
||||
span.alert {
|
||||
color: #D00000;
|
||||
}
|
||||
#nav table {
|
||||
width: 100%;
|
||||
}
|
||||
.detail {
|
||||
padding: 0.25em 1em;
|
||||
background: #F4F4F4;
|
||||
}
|
||||
@@ -1,265 +0,0 @@
|
||||
<!--{
|
||||
"title": "About the go command"
|
||||
}-->
|
||||
|
||||
<p>The Go distribution includes a command, named
|
||||
"<code><a href="/cmd/go/">go</a></code>", that
|
||||
automates the downloading, building, installation, and testing of Go packages
|
||||
and commands. This document talks about why we wrote a new command, what it
|
||||
is, what it's not, and how to use it.</p>
|
||||
|
||||
<h2>Motivation</h2>
|
||||
|
||||
<p>You might have seen early Go talks in which Rob Pike jokes that the idea
|
||||
for Go arose while waiting for a large Google server to compile. That
|
||||
really was the motivation for Go: to build a language that worked well
|
||||
for building the large software that Google writes and runs. It was
|
||||
clear from the start that such a language must provide a way to
|
||||
express dependencies between code libraries clearly, hence the package
|
||||
grouping and the explicit import blocks. It was also clear from the
|
||||
start that you might want arbitrary syntax for describing the code
|
||||
being imported; this is why import paths are string literals.</p>
|
||||
|
||||
<p>An explicit goal for Go from the beginning was to be able to build Go
|
||||
code using only the information found in the source itself, not
|
||||
needing to write a makefile or one of the many modern replacements for
|
||||
makefiles. If Go needed a configuration file to explain how to build
|
||||
your program, then Go would have failed.</p>
|
||||
|
||||
<p>At first, there was no Go compiler, and the initial development
|
||||
focused on building one and then building libraries for it. For
|
||||
expedience, we postponed the automation of building Go code by using
|
||||
make and writing makefiles. When compiling a single package involved
|
||||
multiple invocations of the Go compiler, we even used a program to
|
||||
write the makefiles for us. You can find it if you dig through the
|
||||
repository history.</p>
|
||||
|
||||
<p>The purpose of the new go command is our return to this ideal, that Go
|
||||
programs should compile without configuration or additional effort on
|
||||
the part of the developer beyond writing the necessary import
|
||||
statements.</p>
|
||||
|
||||
<h2>Configuration versus convention</h2>
|
||||
|
||||
<p>The way to achieve the simplicity of a configuration-free system is to
|
||||
establish conventions. The system works only to the extent that those conventions
|
||||
are followed. When we first launched Go, many people published packages that
|
||||
had to be installed in certain places, under certain names, using certain build
|
||||
tools, in order to be used. That's understandable: that's the way it works in
|
||||
most other languages. Over the last few years we consistently reminded people
|
||||
about the <code>goinstall</code> command
|
||||
(now replaced by <a href="/cmd/go/#hdr-Download_and_install_packages_and_dependencies"><code>go get</code></a>)
|
||||
and its conventions: first, that the import path is derived in a known way from
|
||||
the URL of the source code; second, that the place to store the sources in
|
||||
the local file system is derived in a known way from the import path; third,
|
||||
that each directory in a source tree corresponds to a single package; and
|
||||
fourth, that the package is built using only information in the source code.
|
||||
Today, the vast majority of packages follow these conventions.
|
||||
The Go ecosystem is simpler and more powerful as a result.</p>
|
||||
|
||||
<p>We received many requests to allow a makefile in a package directory to
|
||||
provide just a little extra configuration beyond what's in the source code.
|
||||
But that would have introduced new rules. Because we did not accede to such
|
||||
requests, we were able to write the go command and eliminate our use of make
|
||||
or any other build system.</p>
|
||||
|
||||
<p>It is important to understand that the go command is not a general
|
||||
build tool. It cannot be configured and it does not attempt to build
|
||||
anything but Go packages. These are important simplifying
|
||||
assumptions: they simplify not only the implementation but also, more
|
||||
important, the use of the tool itself.</p>
|
||||
|
||||
<h2>Go's conventions</h2>
|
||||
|
||||
<p>The <code>go</code> command requires that code adheres to a few key,
|
||||
well-established conventions.</p>
|
||||
|
||||
<p>First, the import path is derived in an known way from the URL of the
|
||||
source code. For Bitbucket, GitHub, Google Code, and Launchpad, the
|
||||
root directory of the repository is identified by the repository's
|
||||
main URL, without the <code>http://</code> prefix. Subdirectories are named by
|
||||
adding to that path. For example, the supplemental networking
|
||||
libraries for Go are obtained by running</p>
|
||||
|
||||
<pre>
|
||||
hg clone http://code.google.com/p/go.net
|
||||
</pre>
|
||||
|
||||
<p>and thus the import path for the root directory of that repository is
|
||||
"<code>code.google.com/p/go.net</code>". The websocket package is stored in a
|
||||
subdirectory, so its import path is
|
||||
"<code>code.google.com/p/go.net/websocket</code>".</p>
|
||||
|
||||
<p>These paths are on the long side, but in exchange we get an
|
||||
automatically managed name space for import paths and the ability for
|
||||
a tool like the go command to look at an unfamiliar import path and
|
||||
deduce where to obtain the source code.</p>
|
||||
|
||||
<p>Second, the place to store sources in the local file system is derived
|
||||
in a known way from the import path. Specifically, the first choice
|
||||
is <code>$GOPATH/src/<import-path></code>. If <code>$GOPATH</code> is
|
||||
unset, the go command will fall back to storing source code alongside the
|
||||
standard Go packages, in <code>$GOROOT/src/<import-path></code>.
|
||||
If <code>$GOPATH</code> is set to a list of paths, the go command tries
|
||||
<code><dir>/src/<import-path></code> for each of the directories in
|
||||
that list.</p>
|
||||
|
||||
<p>Each of those trees contains, by convention, a top-level directory named
|
||||
"<code>bin</code>", for holding compiled executables, and a top-level directory
|
||||
named "<code>pkg</code>", for holding compiled packages that can be imported,
|
||||
and the "<code>src</code>" directory, for holding package source files.
|
||||
Imposing this structure lets us keep each of these directory trees
|
||||
self-contained: the compiled form and the sources are always near each
|
||||
other.</p>
|
||||
|
||||
<p>These naming conventions also let us work in the reverse direction,
|
||||
from a directory name to its import path. This mapping is important
|
||||
for many of the go command's subcommands, as we'll see below.</p>
|
||||
|
||||
<p>Third, each directory in a source tree corresponds to a single
|
||||
package. By restricting a directory to a single package, we don't have
|
||||
to create hybrid import paths that specify first the directory and
|
||||
then the package within that directory. Also, most file management
|
||||
tools and UIs work on directories as fundamental units. Tying the
|
||||
fundamental Go unit—the package—to file system structure means
|
||||
that file system tools become Go package tools. Copying, moving, or
|
||||
deleting a package corresponds to copying, moving, or deleting a
|
||||
directory.</p>
|
||||
|
||||
<p>Fourth, each package is built using only the information present in
|
||||
the source files. This makes it much more likely that the tool will
|
||||
be able to adapt to changing build environments and conditions. For
|
||||
example, if we allowed extra configuration such as compiler flags or
|
||||
command line recipes, then that configuration would need to be updated
|
||||
each time the build tools changed; it would also be inherently tied
|
||||
to the use of a specific tool chain.</p>
|
||||
|
||||
<h2>Getting started with the go command</h2>
|
||||
|
||||
<p>Finally, a quick tour of how to use the go command, to supplement
|
||||
the information in <a href="/doc/code.html">How to Write Go Code</a>,
|
||||
which you might want to read first. Assuming you want
|
||||
to keep your source code separate from the Go distribution source
|
||||
tree, the first step is to set <code>$GOPATH</code>, the one piece of global
|
||||
configuration that the go command needs. The <code>$GOPATH</code> can be a
|
||||
list of directories, but by far the most common usage should be to set it to a
|
||||
single directory. In particular, you do not need a separate entry in
|
||||
<code>$GOPATH</code> for each of your projects. One <code>$GOPATH</code> can
|
||||
support many projects.</p>
|
||||
|
||||
<p>Here’s an example. Let’s say we decide to keep our Go code in the directory
|
||||
<code>$HOME/mygo</code>. We need to create that directory and set
|
||||
<code>$GOPATH</code> accordingly.</p>
|
||||
|
||||
<pre>
|
||||
$ mkdir $HOME/mygo
|
||||
$ export GOPATH=$HOME/mygo
|
||||
$
|
||||
</pre>
|
||||
|
||||
<p>Into this directory, we now add some source code. Suppose we want to use
|
||||
the indexing library from the codesearch project along with a left-leaning
|
||||
red-black tree. We can install both with the "<code>go get</code>"
|
||||
subcommand:</p>
|
||||
|
||||
<pre>
|
||||
$ go get code.google.com/p/codesearch/index
|
||||
$ go get github.com/petar/GoLLRB/llrb
|
||||
$
|
||||
</pre>
|
||||
|
||||
<p>Both of these projects are now downloaded and installed into our
|
||||
<code>$GOPATH</code> directory. The one tree now contains the two directories
|
||||
<code>src/code.google.com/p/codesearch/index/</code> and
|
||||
<code>src/github.com/petar/GoLLRB/llrb/</code>, along with the compiled
|
||||
packages (in <code>pkg/</code>) for those libraries and their dependencies.</p>
|
||||
|
||||
<p>Because we used version control systems (Mercurial and Git) to check
|
||||
out the sources, the source tree also contains the other files in the
|
||||
corresponding repositories, such as related packages. The "<code>go list</code>"
|
||||
subcommand lists the import paths corresponding to its arguments, and
|
||||
the pattern "<code>./...</code>" means start in the current directory
|
||||
("<code>./</code>") and find all packages below that directory
|
||||
("<code>...</code>"):</p>
|
||||
|
||||
<pre>
|
||||
$ go list ./...
|
||||
code.google.com/p/codesearch/cmd/cgrep
|
||||
code.google.com/p/codesearch/cmd/cindex
|
||||
code.google.com/p/codesearch/cmd/csearch
|
||||
code.google.com/p/codesearch/index
|
||||
code.google.com/p/codesearch/regexp
|
||||
code.google.com/p/codesearch/sparse
|
||||
github.com/petar/GoLLRB/example
|
||||
github.com/petar/GoLLRB/llrb
|
||||
$
|
||||
</pre>
|
||||
|
||||
<p>We can also test those packages:</p>
|
||||
|
||||
<pre>
|
||||
$ go test ./...
|
||||
? code.google.com/p/codesearch/cmd/cgrep [no test files]
|
||||
? code.google.com/p/codesearch/cmd/cindex [no test files]
|
||||
? code.google.com/p/codesearch/cmd/csearch [no test files]
|
||||
ok code.google.com/p/codesearch/index 0.239s
|
||||
ok code.google.com/p/codesearch/regexp 0.021s
|
||||
? code.google.com/p/codesearch/sparse [no test files]
|
||||
? github.com/petar/GoLLRB/example [no test files]
|
||||
ok github.com/petar/GoLLRB/llrb 0.231s
|
||||
$
|
||||
</pre>
|
||||
|
||||
<p>If a go subcommand is invoked with no paths listed, it operates on the
|
||||
current directory:</p>
|
||||
|
||||
<pre>
|
||||
$ cd $GOPATH/src/code.google.com/p/codesearch/regexp
|
||||
$ go list
|
||||
code.google.com/p/codesearch/regexp
|
||||
$ go test -v
|
||||
=== RUN TestNstateEnc
|
||||
--- PASS: TestNstateEnc (0.00 seconds)
|
||||
=== RUN TestMatch
|
||||
--- PASS: TestMatch (0.01 seconds)
|
||||
=== RUN TestGrep
|
||||
--- PASS: TestGrep (0.00 seconds)
|
||||
PASS
|
||||
ok code.google.com/p/codesearch/regexp 0.021s
|
||||
$ go install
|
||||
$
|
||||
</pre>
|
||||
|
||||
<p>That "<code>go install</code>" subcommand installs the latest copy of the
|
||||
package into the pkg directory. Because the go command can analyze the
|
||||
dependency graph, "<code>go install</code>" also installs any packages that
|
||||
this package imports but that are out of date, recursively.</p>
|
||||
|
||||
<p>Notice that "<code>go install</code>" was able to determine the name of the
|
||||
import path for the package in the current directory, because of the convention
|
||||
for directory naming. It would be a little more convenient if we could pick
|
||||
the name of the directory where we kept source code, and we probably wouldn't
|
||||
pick such a long name, but that ability would require additional configuration
|
||||
and complexity in the tool. Typing an extra directory name or two is a small
|
||||
price to pay for the increased simplicity and power.</p>
|
||||
|
||||
<p>As the example shows, it’s fine to work with packages from many different
|
||||
projects at once within a single <code>$GOPATH</code> root directory.</p>
|
||||
|
||||
<h2>Limitations</h2>
|
||||
|
||||
<p>As mentioned above, the go command is not a general-purpose build
|
||||
tool. In particular, it does not have any facility for generating Go
|
||||
source files during a build. Instead, if you want to use a tool like
|
||||
yacc or the protocol buffer compiler, you will need to write a
|
||||
makefile (or a configuration file for the build tool of your choice)
|
||||
to generate the Go files and then check those generated source files
|
||||
into your repository. This is more work for you, the package author,
|
||||
but it is significantly less work for your users, who can use
|
||||
"<code>go get</code>" without needing to obtain and build
|
||||
any additional tools.</p>
|
||||
|
||||
<h2>More information</h2>
|
||||
|
||||
<p>For more information, read <a href="/doc/code.html">How to Write Go Code</a>
|
||||
and see the <a href="/cmd/go/">go command documentation</a>.</p>
|
||||
@@ -1,8 +0,0 @@
|
||||
<!--{
|
||||
"Title": "/doc/articles/"
|
||||
}-->
|
||||
|
||||
<p>
|
||||
See the <a href="/doc/#articles">Documents page</a> and the
|
||||
<a href="/blog/index">Blog index</a> for a complete list of Go articles.
|
||||
</p>
|
||||
@@ -1,389 +0,0 @@
|
||||
<!--{
|
||||
"Title": "Data Race Detector",
|
||||
"Template": true
|
||||
}-->
|
||||
|
||||
<h2 id="Introduction">Introduction</h2>
|
||||
|
||||
<p>
|
||||
Data races are among the most common and hardest to debug types of bugs in concurrent systems.
|
||||
A data race occurs when two goroutines access the same variable concurrently and at least one of the accesses is a write.
|
||||
See the <a href="/ref/mem/">The Go Memory Model</a> for details.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Here is an example of a data race that can lead to crashes and memory corruption:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
func main() {
|
||||
c := make(chan bool)
|
||||
m := make(map[string]string)
|
||||
go func() {
|
||||
m["1"] = "a" // First conflicting access.
|
||||
c <- true
|
||||
}()
|
||||
m["2"] = "b" // Second conflicting access.
|
||||
<-c
|
||||
for k, v := range m {
|
||||
fmt.Println(k, v)
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
|
||||
<h2 id="Usage">Usage</h2>
|
||||
|
||||
<p>
|
||||
To help diagnose such bugs, Go includes a built-in data race detector.
|
||||
To use it, add the <code>-race</code> flag to the go command:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
$ go test -race mypkg // to test the package
|
||||
$ go run -race mysrc.go // to run the source file
|
||||
$ go build -race mycmd // to build the command
|
||||
$ go install -race mypkg // to install the package
|
||||
</pre>
|
||||
|
||||
<h2 id="Report_Format">Report Format</h2>
|
||||
|
||||
<p>
|
||||
When the race detector finds a data race in the program, it prints a report.
|
||||
The report contains stack traces for conflicting accesses, as well as stacks where the involved goroutines were created.
|
||||
Here is an example:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
WARNING: DATA RACE
|
||||
Read by goroutine 185:
|
||||
net.(*pollServer).AddFD()
|
||||
src/net/fd_unix.go:89 +0x398
|
||||
net.(*pollServer).WaitWrite()
|
||||
src/net/fd_unix.go:247 +0x45
|
||||
net.(*netFD).Write()
|
||||
src/net/fd_unix.go:540 +0x4d4
|
||||
net.(*conn).Write()
|
||||
src/net/net.go:129 +0x101
|
||||
net.func·060()
|
||||
src/net/timeout_test.go:603 +0xaf
|
||||
|
||||
Previous write by goroutine 184:
|
||||
net.setWriteDeadline()
|
||||
src/net/sockopt_posix.go:135 +0xdf
|
||||
net.setDeadline()
|
||||
src/net/sockopt_posix.go:144 +0x9c
|
||||
net.(*conn).SetDeadline()
|
||||
src/net/net.go:161 +0xe3
|
||||
net.func·061()
|
||||
src/net/timeout_test.go:616 +0x3ed
|
||||
|
||||
Goroutine 185 (running) created at:
|
||||
net.func·061()
|
||||
src/net/timeout_test.go:609 +0x288
|
||||
|
||||
Goroutine 184 (running) created at:
|
||||
net.TestProlongTimeout()
|
||||
src/net/timeout_test.go:618 +0x298
|
||||
testing.tRunner()
|
||||
src/testing/testing.go:301 +0xe8
|
||||
</pre>
|
||||
|
||||
<h2 id="Options">Options</h2>
|
||||
|
||||
<p>
|
||||
The <code>GORACE</code> environment variable sets race detector options.
|
||||
The format is:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
GORACE="option1=val1 option2=val2"
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The options are:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<code>log_path</code> (default <code>stderr</code>): The race detector writes
|
||||
its report to a file named <code>log_path.<em>pid</em></code>.
|
||||
The special names <code>stdout</code>
|
||||
and <code>stderr</code> cause reports to be written to standard output and
|
||||
standard error, respectively.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<code>exitcode</code> (default <code>66</code>): The exit status to use when
|
||||
exiting after a detected race.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<code>strip_path_prefix</code> (default <code>""</code>): Strip this prefix
|
||||
from all reported file paths, to make reports more concise.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<code>history_size</code> (default <code>1</code>): The per-goroutine memory
|
||||
access history is <code>32K * 2**history_size elements</code>.
|
||||
Increasing this value can avoid a "failed to restore the stack" error in reports, at the
|
||||
cost of increased memory usage.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<code>halt_on_error</code> (default <code>0</code>): Controls whether the program
|
||||
exits after reporting first data race.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
Example:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
$ GORACE="log_path=/tmp/race/report strip_path_prefix=/my/go/sources/" go test -race
|
||||
</pre>
|
||||
|
||||
<h2 id="Excluding_Tests">Excluding Tests</h2>
|
||||
|
||||
<p>
|
||||
When you build with <code>-race</code> flag, the <code>go</code> command defines additional
|
||||
<a href="/pkg/go/build/#hdr-Build_Constraints">build tag</a> <code>race</code>.
|
||||
You can use the tag to exclude some code and tests when running the race detector.
|
||||
Some examples:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
// +build !race
|
||||
|
||||
package foo
|
||||
|
||||
// The test contains a data race. See issue 123.
|
||||
func TestFoo(t *testing.T) {
|
||||
// ...
|
||||
}
|
||||
|
||||
// The test fails under the race detector due to timeouts.
|
||||
func TestBar(t *testing.T) {
|
||||
// ...
|
||||
}
|
||||
|
||||
// The test takes too long under the race detector.
|
||||
func TestBaz(t *testing.T) {
|
||||
// ...
|
||||
}
|
||||
</pre>
|
||||
|
||||
<h2 id="How_To_Use">How To Use</h2>
|
||||
|
||||
<p>
|
||||
To start, run your tests using the race detector (<code>go test -race</code>).
|
||||
The race detector only finds races that happen at runtime, so it can't find
|
||||
races in code paths that are not executed.
|
||||
If your tests have incomplete coverage,
|
||||
you may find more races by running a binary built with <code>-race</code> under a realistic
|
||||
workload.
|
||||
</p>
|
||||
|
||||
<h2 id="Typical_Data_Races">Typical Data Races</h2>
|
||||
|
||||
<p>
|
||||
Here are some typical data races. All of them can be detected with the race detector.
|
||||
</p>
|
||||
|
||||
<h3 id="Race_on_loop_counter">Race on loop counter</h3>
|
||||
|
||||
<pre>
|
||||
func main() {
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(5)
|
||||
for i := 0; i < 5; i++ {
|
||||
go func() {
|
||||
fmt.Println(i) // Not the 'i' you are looking for.
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The variable <code>i</code> in the function literal is the same variable used by the loop, so
|
||||
the read in the goroutine races with the loop increment.
|
||||
(This program typically prints 55555, not 01234.)
|
||||
The program can be fixed by making a copy of the variable:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
func main() {
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(5)
|
||||
for i := 0; i < 5; i++ {
|
||||
go func(j int) {
|
||||
fmt.Println(j) // Good. Read local copy of the loop counter.
|
||||
wg.Done()
|
||||
}(i)
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
</pre>
|
||||
|
||||
<h3 id="Accidentally_shared_variable">Accidentally shared variable</h3>
|
||||
|
||||
<pre>
|
||||
// ParallelWrite writes data to file1 and file2, returns the errors.
|
||||
func ParallelWrite(data []byte) chan error {
|
||||
res := make(chan error, 2)
|
||||
f1, err := os.Create("file1")
|
||||
if err != nil {
|
||||
res <- err
|
||||
} else {
|
||||
go func() {
|
||||
// This err is shared with the main goroutine,
|
||||
// so the write races with the write below.
|
||||
_, err = f1.Write(data)
|
||||
res <- err
|
||||
f1.Close()
|
||||
}()
|
||||
}
|
||||
f2, err := os.Create("file2") // The second conflicting write to err.
|
||||
if err != nil {
|
||||
res <- err
|
||||
} else {
|
||||
go func() {
|
||||
_, err = f2.Write(data)
|
||||
res <- err
|
||||
f2.Close()
|
||||
}()
|
||||
}
|
||||
return res
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The fix is to introduce new variables in the goroutines (note the use of <code>:=</code>):
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
...
|
||||
_, err := f1.Write(data)
|
||||
...
|
||||
_, err := f2.Write(data)
|
||||
...
|
||||
</pre>
|
||||
|
||||
<h3 id="Unprotected_global_variable">Unprotected global variable</h3>
|
||||
|
||||
<p>
|
||||
If the following code is called from several goroutines, it leads to races on the <code>service</code> map.
|
||||
Concurrent reads and writes of the same map are not safe:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
var service map[string]net.Addr
|
||||
|
||||
func RegisterService(name string, addr net.Addr) {
|
||||
service[name] = addr
|
||||
}
|
||||
|
||||
func LookupService(name string) net.Addr {
|
||||
return service[name]
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
To make the code safe, protect the accesses with a mutex:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
var (
|
||||
service map[string]net.Addr
|
||||
serviceMu sync.Mutex
|
||||
)
|
||||
|
||||
func RegisterService(name string, addr net.Addr) {
|
||||
serviceMu.Lock()
|
||||
defer serviceMu.Unlock()
|
||||
service[name] = addr
|
||||
}
|
||||
|
||||
func LookupService(name string) net.Addr {
|
||||
serviceMu.Lock()
|
||||
defer serviceMu.Unlock()
|
||||
return service[name]
|
||||
}
|
||||
</pre>
|
||||
|
||||
<h3 id="Primitive_unprotected_variable">Primitive unprotected variable</h3>
|
||||
|
||||
<p>
|
||||
Data races can happen on variables of primitive types as well (<code>bool</code>, <code>int</code>, <code>int64</code>, etc.),
|
||||
as in this example:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
type Watchdog struct{ last int64 }
|
||||
|
||||
func (w *Watchdog) KeepAlive() {
|
||||
w.last = time.Now().UnixNano() // First conflicting access.
|
||||
}
|
||||
|
||||
func (w *Watchdog) Start() {
|
||||
go func() {
|
||||
for {
|
||||
time.Sleep(time.Second)
|
||||
// Second conflicting access.
|
||||
if w.last < time.Now().Add(-10*time.Second).UnixNano() {
|
||||
fmt.Println("No keepalives for 10 seconds. Dying.")
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Even such "innocent" data races can lead to hard-to-debug problems caused by
|
||||
non-atomicity of the memory accesses,
|
||||
interference with compiler optimizations,
|
||||
or reordering issues accessing processor memory .
|
||||
</p>
|
||||
|
||||
<p>
|
||||
A typical fix for this race is to use a channel or a mutex.
|
||||
To preserve the lock-free behavior, one can also use the
|
||||
<a href="/pkg/sync/atomic/"><code>sync/atomic</code></a> package.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
type Watchdog struct{ last int64 }
|
||||
|
||||
func (w *Watchdog) KeepAlive() {
|
||||
atomic.StoreInt64(&w.last, time.Now().UnixNano())
|
||||
}
|
||||
|
||||
func (w *Watchdog) Start() {
|
||||
go func() {
|
||||
for {
|
||||
time.Sleep(time.Second)
|
||||
if atomic.LoadInt64(&w.last) < time.Now().Add(-10*time.Second).UnixNano() {
|
||||
fmt.Println("No keepalives for 10 seconds. Dying.")
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
</pre>
|
||||
|
||||
<h2 id="Supported_Systems">Supported Systems</h2>
|
||||
|
||||
<p>
|
||||
The race detector runs on <code>darwin/amd64</code>, <code>freebsd/amd64</code>,
|
||||
<code>linux/amd64</code>, and <code>windows/amd64</code>.
|
||||
</p>
|
||||
|
||||
<h2 id="Runtime_Overheads">Runtime Overhead</h2>
|
||||
|
||||
<p>
|
||||
The cost of race detection varies by program, but for a typical program, memory
|
||||
usage may increase by 5-10x and execution time by 2-20x.
|
||||
</p>
|
||||
@@ -1,6 +0,0 @@
|
||||
<h1>Editing {{.Title}}</h1>
|
||||
|
||||
<form action="/save/{{.Title}}" method="POST">
|
||||
<div><textarea name="body" rows="20" cols="80">{{printf "%s" .Body}}</textarea></div>
|
||||
<div><input type="submit" value="Save"></div>
|
||||
</form>
|
||||
@@ -1,102 +0,0 @@
|
||||
// Copyright 2010 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"html/template"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
type Page struct {
|
||||
Title string
|
||||
Body []byte
|
||||
}
|
||||
|
||||
func (p *Page) save() error {
|
||||
filename := p.Title + ".txt"
|
||||
return ioutil.WriteFile(filename, p.Body, 0600)
|
||||
}
|
||||
|
||||
func loadPage(title string) (*Page, error) {
|
||||
filename := title + ".txt"
|
||||
body, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Page{Title: title, Body: body}, nil
|
||||
}
|
||||
|
||||
func viewHandler(w http.ResponseWriter, r *http.Request) {
|
||||
title, err := getTitle(w, r)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
p, err := loadPage(title)
|
||||
if err != nil {
|
||||
http.Redirect(w, r, "/edit/"+title, http.StatusFound)
|
||||
return
|
||||
}
|
||||
renderTemplate(w, "view", p)
|
||||
}
|
||||
|
||||
func editHandler(w http.ResponseWriter, r *http.Request) {
|
||||
title, err := getTitle(w, r)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
p, err := loadPage(title)
|
||||
if err != nil {
|
||||
p = &Page{Title: title}
|
||||
}
|
||||
renderTemplate(w, "edit", p)
|
||||
}
|
||||
|
||||
func saveHandler(w http.ResponseWriter, r *http.Request) {
|
||||
title, err := getTitle(w, r)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
body := r.FormValue("body")
|
||||
p := &Page{Title: title, Body: []byte(body)}
|
||||
err = p.save()
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
http.Redirect(w, r, "/view/"+title, http.StatusFound)
|
||||
}
|
||||
|
||||
func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) {
|
||||
t, err := template.ParseFiles(tmpl + ".html")
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
err = t.Execute(w, p)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
var validPath = regexp.MustCompile("^/(edit|save|view)/([a-zA-Z0-9]+)$")
|
||||
|
||||
func getTitle(w http.ResponseWriter, r *http.Request) (string, error) {
|
||||
m := validPath.FindStringSubmatch(r.URL.Path)
|
||||
if m == nil {
|
||||
http.NotFound(w, r)
|
||||
return "", errors.New("Invalid Page Title")
|
||||
}
|
||||
return m[2], nil // The title is the second subexpression.
|
||||
}
|
||||
|
||||
func main() {
|
||||
http.HandleFunc("/view/", viewHandler)
|
||||
http.HandleFunc("/edit/", editHandler)
|
||||
http.HandleFunc("/save/", saveHandler)
|
||||
http.ListenAndServe(":8080", nil)
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
// Copyright 2010 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"html/template"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type Page struct {
|
||||
Title string
|
||||
Body []byte
|
||||
}
|
||||
|
||||
func (p *Page) save() error {
|
||||
filename := p.Title + ".txt"
|
||||
return ioutil.WriteFile(filename, p.Body, 0600)
|
||||
}
|
||||
|
||||
func loadPage(title string) (*Page, error) {
|
||||
filename := title + ".txt"
|
||||
body, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Page{Title: title, Body: body}, nil
|
||||
}
|
||||
|
||||
func editHandler(w http.ResponseWriter, r *http.Request) {
|
||||
title := r.URL.Path[len("/edit/"):]
|
||||
p, err := loadPage(title)
|
||||
if err != nil {
|
||||
p = &Page{Title: title}
|
||||
}
|
||||
t, _ := template.ParseFiles("edit.html")
|
||||
t.Execute(w, p)
|
||||
}
|
||||
|
||||
func viewHandler(w http.ResponseWriter, r *http.Request) {
|
||||
title := r.URL.Path[len("/view/"):]
|
||||
p, _ := loadPage(title)
|
||||
t, _ := template.ParseFiles("view.html")
|
||||
t.Execute(w, p)
|
||||
}
|
||||
|
||||
func main() {
|
||||
http.HandleFunc("/view/", viewHandler)
|
||||
http.HandleFunc("/edit/", editHandler)
|
||||
http.ListenAndServe(":8080", nil)
|
||||
}
|
||||
@@ -1,91 +0,0 @@
|
||||
// Copyright 2010 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"html/template"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
type Page struct {
|
||||
Title string
|
||||
Body []byte
|
||||
}
|
||||
|
||||
func (p *Page) save() error {
|
||||
filename := p.Title + ".txt"
|
||||
return ioutil.WriteFile(filename, p.Body, 0600)
|
||||
}
|
||||
|
||||
func loadPage(title string) (*Page, error) {
|
||||
filename := title + ".txt"
|
||||
body, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Page{Title: title, Body: body}, nil
|
||||
}
|
||||
|
||||
func viewHandler(w http.ResponseWriter, r *http.Request, title string) {
|
||||
p, err := loadPage(title)
|
||||
if err != nil {
|
||||
http.Redirect(w, r, "/edit/"+title, http.StatusFound)
|
||||
return
|
||||
}
|
||||
renderTemplate(w, "view", p)
|
||||
}
|
||||
|
||||
func editHandler(w http.ResponseWriter, r *http.Request, title string) {
|
||||
p, err := loadPage(title)
|
||||
if err != nil {
|
||||
p = &Page{Title: title}
|
||||
}
|
||||
renderTemplate(w, "edit", p)
|
||||
}
|
||||
|
||||
func saveHandler(w http.ResponseWriter, r *http.Request, title string) {
|
||||
body := r.FormValue("body")
|
||||
p := &Page{Title: title, Body: []byte(body)}
|
||||
err := p.save()
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
http.Redirect(w, r, "/view/"+title, http.StatusFound)
|
||||
}
|
||||
|
||||
func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) {
|
||||
t, err := template.ParseFiles(tmpl + ".html")
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
err = t.Execute(w, p)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
var validPath = regexp.MustCompile("^/(edit|save|view)/([a-zA-Z0-9]+)$")
|
||||
|
||||
func makeHandler(fn func(http.ResponseWriter, *http.Request, string)) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
m := validPath.FindStringSubmatch(r.URL.Path)
|
||||
if m == nil {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
fn(w, r, m[2])
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
http.HandleFunc("/view/", makeHandler(viewHandler))
|
||||
http.HandleFunc("/edit/", makeHandler(editHandler))
|
||||
http.HandleFunc("/save/", makeHandler(saveHandler))
|
||||
http.ListenAndServe(":8080", nil)
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
// Copyright 2010 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"html/template"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type Page struct {
|
||||
Title string
|
||||
Body []byte
|
||||
}
|
||||
|
||||
func (p *Page) save() error {
|
||||
filename := p.Title + ".txt"
|
||||
return ioutil.WriteFile(filename, p.Body, 0600)
|
||||
}
|
||||
|
||||
func loadPage(title string) (*Page, error) {
|
||||
filename := title + ".txt"
|
||||
body, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Page{Title: title, Body: body}, nil
|
||||
}
|
||||
|
||||
func editHandler(w http.ResponseWriter, r *http.Request) {
|
||||
title := r.URL.Path[len("/edit/"):]
|
||||
p, err := loadPage(title)
|
||||
if err != nil {
|
||||
p = &Page{Title: title}
|
||||
}
|
||||
renderTemplate(w, "edit", p)
|
||||
}
|
||||
|
||||
func viewHandler(w http.ResponseWriter, r *http.Request) {
|
||||
title := r.URL.Path[len("/view/"):]
|
||||
p, _ := loadPage(title)
|
||||
renderTemplate(w, "view", p)
|
||||
}
|
||||
|
||||
func saveHandler(w http.ResponseWriter, r *http.Request) {
|
||||
title := r.URL.Path[len("/save/"):]
|
||||
body := r.FormValue("body")
|
||||
p := &Page{Title: title, Body: []byte(body)}
|
||||
p.save()
|
||||
http.Redirect(w, r, "/view/"+title, http.StatusFound)
|
||||
}
|
||||
|
||||
func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) {
|
||||
t, _ := template.ParseFiles(tmpl + ".html")
|
||||
t.Execute(w, p)
|
||||
}
|
||||
|
||||
func main() {
|
||||
http.HandleFunc("/view/", viewHandler)
|
||||
http.HandleFunc("/edit/", editHandler)
|
||||
http.HandleFunc("/save/", saveHandler)
|
||||
http.ListenAndServe(":8080", nil)
|
||||
}
|
||||
@@ -1,111 +0,0 @@
|
||||
// Copyright 2010 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"html/template"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
var (
|
||||
addr = flag.Bool("addr", false, "find open address and print to final-port.txt")
|
||||
)
|
||||
|
||||
type Page struct {
|
||||
Title string
|
||||
Body []byte
|
||||
}
|
||||
|
||||
func (p *Page) save() error {
|
||||
filename := p.Title + ".txt"
|
||||
return ioutil.WriteFile(filename, p.Body, 0600)
|
||||
}
|
||||
|
||||
func loadPage(title string) (*Page, error) {
|
||||
filename := title + ".txt"
|
||||
body, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Page{Title: title, Body: body}, nil
|
||||
}
|
||||
|
||||
func viewHandler(w http.ResponseWriter, r *http.Request, title string) {
|
||||
p, err := loadPage(title)
|
||||
if err != nil {
|
||||
http.Redirect(w, r, "/edit/"+title, http.StatusFound)
|
||||
return
|
||||
}
|
||||
renderTemplate(w, "view", p)
|
||||
}
|
||||
|
||||
func editHandler(w http.ResponseWriter, r *http.Request, title string) {
|
||||
p, err := loadPage(title)
|
||||
if err != nil {
|
||||
p = &Page{Title: title}
|
||||
}
|
||||
renderTemplate(w, "edit", p)
|
||||
}
|
||||
|
||||
func saveHandler(w http.ResponseWriter, r *http.Request, title string) {
|
||||
body := r.FormValue("body")
|
||||
p := &Page{Title: title, Body: []byte(body)}
|
||||
err := p.save()
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
http.Redirect(w, r, "/view/"+title, http.StatusFound)
|
||||
}
|
||||
|
||||
var templates = template.Must(template.ParseFiles("edit.html", "view.html"))
|
||||
|
||||
func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) {
|
||||
err := templates.ExecuteTemplate(w, tmpl+".html", p)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
var validPath = regexp.MustCompile("^/(edit|save|view)/([a-zA-Z0-9]+)$")
|
||||
|
||||
func makeHandler(fn func(http.ResponseWriter, *http.Request, string)) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
m := validPath.FindStringSubmatch(r.URL.Path)
|
||||
if m == nil {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
fn(w, r, m[2])
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
http.HandleFunc("/view/", makeHandler(viewHandler))
|
||||
http.HandleFunc("/edit/", makeHandler(editHandler))
|
||||
http.HandleFunc("/save/", makeHandler(saveHandler))
|
||||
|
||||
if *addr {
|
||||
l, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
err = ioutil.WriteFile("final-port.txt", []byte(l.Addr().String()), 0644)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
s := &http.Server{}
|
||||
s.Serve(l)
|
||||
return
|
||||
}
|
||||
|
||||
http.ListenAndServe(":8080", nil)
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
post = flag.String("post", "", "urlencoded form data to POST")
|
||||
addr = flag.Bool("addr", false, "find open address and print to stdout")
|
||||
wait = flag.Duration("wait_for_port", 0, "if non-zero, the amount of time to wait for the address to become available")
|
||||
)
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
if *addr {
|
||||
l, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer l.Close()
|
||||
fmt.Print(l.Addr())
|
||||
return
|
||||
}
|
||||
url := flag.Arg(0)
|
||||
if url == "" {
|
||||
log.Fatal("no url supplied")
|
||||
}
|
||||
var r *http.Response
|
||||
var err error
|
||||
loopUntil := time.Now().Add(*wait)
|
||||
for {
|
||||
if *post != "" {
|
||||
b := strings.NewReader(*post)
|
||||
r, err = http.Post(url, "application/x-www-form-urlencoded", b)
|
||||
} else {
|
||||
r, err = http.Get(url)
|
||||
}
|
||||
if err == nil || *wait == 0 || time.Now().After(loopUntil) {
|
||||
break
|
||||
}
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer r.Body.Close()
|
||||
_, err = io.Copy(os.Stdout, r.Body)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
@@ -1,734 +0,0 @@
|
||||
<!--{
|
||||
"Title": "Writing Web Applications",
|
||||
"Template": true
|
||||
}-->
|
||||
|
||||
<h2>Introduction</h2>
|
||||
|
||||
<p>
|
||||
Covered in this tutorial:
|
||||
</p>
|
||||
<ul>
|
||||
<li>Creating a data structure with load and save methods</li>
|
||||
<li>Using the <code>net/http</code> package to build web applications
|
||||
<li>Using the <code>html/template</code> package to process HTML templates</li>
|
||||
<li>Using the <code>regexp</code> package to validate user input</li>
|
||||
<li>Using closures</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
Assumed knowledge:
|
||||
</p>
|
||||
<ul>
|
||||
<li>Programming experience</li>
|
||||
<li>Understanding of basic web technologies (HTTP, HTML)</li>
|
||||
<li>Some UNIX/DOS command-line knowledge</li>
|
||||
</ul>
|
||||
|
||||
<h2>Getting Started</h2>
|
||||
|
||||
<p>
|
||||
At present, you need to have a FreeBSD, Linux, OS X, or Windows machine to run Go.
|
||||
We will use <code>$</code> to represent the command prompt.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Install Go (see the <a href="/doc/install">Installation Instructions</a>).
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Make a new directory for this tutorial inside your <code>GOPATH</code> and cd to it:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
$ mkdir gowiki
|
||||
$ cd gowiki
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Create a file named <code>wiki.go</code>, open it in your favorite editor, and
|
||||
add the following lines:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
)
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
We import the <code>fmt</code> and <code>ioutil</code> packages from the Go
|
||||
standard library. Later, as we implement additional functionality, we will
|
||||
add more packages to this <code>import</code> declaration.
|
||||
</p>
|
||||
|
||||
<h2>Data Structures</h2>
|
||||
|
||||
<p>
|
||||
Let's start by defining the data structures. A wiki consists of a series of
|
||||
interconnected pages, each of which has a title and a body (the page content).
|
||||
Here, we define <code>Page</code> as a struct with two fields representing
|
||||
the title and body.
|
||||
</p>
|
||||
|
||||
{{code "doc/articles/wiki/part1.go" `/^type Page/` `/}/`}}
|
||||
|
||||
<p>
|
||||
The type <code>[]byte</code> means "a <code>byte</code> slice".
|
||||
(See <a href="/doc/articles/slices_usage_and_internals.html">Slices: usage and
|
||||
internals</a> for more on slices.)
|
||||
The <code>Body</code> element is a <code>[]byte</code> rather than
|
||||
<code>string</code> because that is the type expected by the <code>io</code>
|
||||
libraries we will use, as you'll see below.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The <code>Page</code> struct describes how page data will be stored in memory.
|
||||
But what about persistent storage? We can address that by creating a
|
||||
<code>save</code> method on <code>Page</code>:
|
||||
</p>
|
||||
|
||||
{{code "doc/articles/wiki/part1.go" `/^func.*Page.*save/` `/}/`}}
|
||||
|
||||
<p>
|
||||
This method's signature reads: "This is a method named <code>save</code> that
|
||||
takes as its receiver <code>p</code>, a pointer to <code>Page</code> . It takes
|
||||
no parameters, and returns a value of type <code>error</code>."
|
||||
</p>
|
||||
|
||||
<p>
|
||||
This method will save the <code>Page</code>'s <code>Body</code> to a text
|
||||
file. For simplicity, we will use the <code>Title</code> as the file name.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The <code>save</code> method returns an <code>error</code> value because
|
||||
that is the return type of <code>WriteFile</code> (a standard library function
|
||||
that writes a byte slice to a file). The <code>save</code> method returns the
|
||||
error value, to let the application handle it should anything go wrong while
|
||||
writing the file. If all goes well, <code>Page.save()</code> will return
|
||||
<code>nil</code> (the zero-value for pointers, interfaces, and some other
|
||||
types).
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The octal integer literal <code>0600</code>, passed as the third parameter to
|
||||
<code>WriteFile</code>, indicates that the file should be created with
|
||||
read-write permissions for the current user only. (See the Unix man page
|
||||
<code>open(2)</code> for details.)
|
||||
</p>
|
||||
|
||||
<p>
|
||||
In addition to saving pages, we will want to load pages, too:
|
||||
</p>
|
||||
|
||||
{{code "doc/articles/wiki/part1-noerror.go" `/^func loadPage/` `/^}/`}}
|
||||
|
||||
<p>
|
||||
The function <code>loadPage</code> constructs the file name from the title
|
||||
parameter, reads the file's contents into a new variable <code>body</code>, and
|
||||
returns a pointer to a <code>Page</code> literal constructed with the proper
|
||||
title and body values.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Functions can return multiple values. The standard library function
|
||||
<code>io.ReadFile</code> returns <code>[]byte</code> and <code>error</code>.
|
||||
In <code>loadPage</code>, error isn't being handled yet; the "blank identifier"
|
||||
represented by the underscore (<code>_</code>) symbol is used to throw away the
|
||||
error return value (in essence, assigning the value to nothing).
|
||||
</p>
|
||||
|
||||
<p>
|
||||
But what happens if <code>ReadFile</code> encounters an error? For example,
|
||||
the file might not exist. We should not ignore such errors. Let's modify the
|
||||
function to return <code>*Page</code> and <code>error</code>.
|
||||
</p>
|
||||
|
||||
{{code "doc/articles/wiki/part1.go" `/^func loadPage/` `/^}/`}}
|
||||
|
||||
<p>
|
||||
Callers of this function can now check the second parameter; if it is
|
||||
<code>nil</code> then it has successfully loaded a Page. If not, it will be an
|
||||
<code>error</code> that can be handled by the caller (see the
|
||||
<a href="/ref/spec#Errors">language specification</a> for details).
|
||||
</p>
|
||||
|
||||
<p>
|
||||
At this point we have a simple data structure and the ability to save to and
|
||||
load from a file. Let's write a <code>main</code> function to test what we've
|
||||
written:
|
||||
</p>
|
||||
|
||||
{{code "doc/articles/wiki/part1.go" `/^func main/` `/^}/`}}
|
||||
|
||||
<p>
|
||||
After compiling and executing this code, a file named <code>TestPage.txt</code>
|
||||
would be created, containing the contents of <code>p1</code>. The file would
|
||||
then be read into the struct <code>p2</code>, and its <code>Body</code> element
|
||||
printed to the screen.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
You can compile and run the program like this:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
$ go build wiki.go
|
||||
$ ./wiki
|
||||
This is a sample page.
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
(If you're using Windows you must type "<code>wiki</code>" without the
|
||||
"<code>./</code>" to run the program.)
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<a href="part1.go">Click here to view the code we've written so far.</a>
|
||||
</p>
|
||||
|
||||
<h2>Introducing the <code>net/http</code> package (an interlude)</h2>
|
||||
|
||||
<p>
|
||||
Here's a full working example of a simple web server:
|
||||
</p>
|
||||
|
||||
{{code "doc/articles/wiki/http-sample.go"}}
|
||||
|
||||
<p>
|
||||
The <code>main</code> function begins with a call to
|
||||
<code>http.HandleFunc</code>, which tells the <code>http</code> package to
|
||||
handle all requests to the web root (<code>"/"</code>) with
|
||||
<code>handler</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
It then calls <code>http.ListenAndServe</code>, specifying that it should
|
||||
listen on port 8080 on any interface (<code>":8080"</code>). (Don't
|
||||
worry about its second parameter, <code>nil</code>, for now.)
|
||||
This function will block until the program is terminated.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The function <code>handler</code> is of the type <code>http.HandlerFunc</code>.
|
||||
It takes an <code>http.ResponseWriter</code> and an <code>http.Request</code> as
|
||||
its arguments.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
An <code>http.ResponseWriter</code> value assembles the HTTP server's response; by writing
|
||||
to it, we send data to the HTTP client.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
An <code>http.Request</code> is a data structure that represents the client
|
||||
HTTP request. <code>r.URL.Path</code> is the path component
|
||||
of the request URL. The trailing <code>[1:]</code> means
|
||||
"create a sub-slice of <code>Path</code> from the 1st character to the end."
|
||||
This drops the leading "/" from the path name.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If you run this program and access the URL:
|
||||
</p>
|
||||
<pre>http://localhost:8080/monkeys</pre>
|
||||
<p>
|
||||
the program would present a page containing:
|
||||
</p>
|
||||
<pre>Hi there, I love monkeys!</pre>
|
||||
|
||||
<h2>Using <code>net/http</code> to serve wiki pages</h2>
|
||||
|
||||
<p>
|
||||
To use the <code>net/http</code> package, it must be imported:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
<b>"net/http"</b>
|
||||
)
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Let's create a handler, <code>viewHandler</code> that will allow users to
|
||||
view a wiki page. It will handle URLs prefixed with "/view/".
|
||||
</p>
|
||||
|
||||
{{code "doc/articles/wiki/part2.go" `/^func viewHandler/` `/^}/`}}
|
||||
|
||||
<p>
|
||||
First, this function extracts the page title from <code>r.URL.Path</code>,
|
||||
the path component of the request URL.
|
||||
The <code>Path</code> is re-sliced with <code>[len("/view/"):]</code> to drop
|
||||
the leading <code>"/view/"</code> component of the request path.
|
||||
This is because the path will invariably begin with <code>"/view/"</code>,
|
||||
which is not part of the page's title.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The function then loads the page data, formats the page with a string of simple
|
||||
HTML, and writes it to <code>w</code>, the <code>http.ResponseWriter</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Again, note the use of <code>_</code> to ignore the <code>error</code>
|
||||
return value from <code>loadPage</code>. This is done here for simplicity
|
||||
and generally considered bad practice. We will attend to this later.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
To use this handler, we rewrite our <code>main</code> function to
|
||||
initialize <code>http</code> using the <code>viewHandler</code> to handle
|
||||
any requests under the path <code>/view/</code>.
|
||||
</p>
|
||||
|
||||
{{code "doc/articles/wiki/part2.go" `/^func main/` `/^}/`}}
|
||||
|
||||
<p>
|
||||
<a href="part2.go">Click here to view the code we've written so far.</a>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Let's create some page data (as <code>test.txt</code>), compile our code, and
|
||||
try serving a wiki page.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Open <code>test.txt</code> file in your editor, and save the string "Hello world" (without quotes)
|
||||
in it.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
$ go build wiki.go
|
||||
$ ./wiki
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
(If you're using Windows you must type "<code>wiki</code>" without the
|
||||
"<code>./</code>" to run the program.)
|
||||
</p>
|
||||
|
||||
<p>
|
||||
With this web server running, a visit to <code><a
|
||||
href="http://localhost:8080/view/test">http://localhost:8080/view/test</a></code>
|
||||
should show a page titled "test" containing the words "Hello world".
|
||||
</p>
|
||||
|
||||
<h2>Editing Pages</h2>
|
||||
|
||||
<p>
|
||||
A wiki is not a wiki without the ability to edit pages. Let's create two new
|
||||
handlers: one named <code>editHandler</code> to display an 'edit page' form,
|
||||
and the other named <code>saveHandler</code> to save the data entered via the
|
||||
form.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
First, we add them to <code>main()</code>:
|
||||
</p>
|
||||
|
||||
{{code "doc/articles/wiki/final-noclosure.go" `/^func main/` `/^}/`}}
|
||||
|
||||
<p>
|
||||
The function <code>editHandler</code> loads the page
|
||||
(or, if it doesn't exist, create an empty <code>Page</code> struct),
|
||||
and displays an HTML form.
|
||||
</p>
|
||||
|
||||
{{code "doc/articles/wiki/notemplate.go" `/^func editHandler/` `/^}/`}}
|
||||
|
||||
<p>
|
||||
This function will work fine, but all that hard-coded HTML is ugly.
|
||||
Of course, there is a better way.
|
||||
</p>
|
||||
|
||||
<h2>The <code>html/template</code> package</h2>
|
||||
|
||||
<p>
|
||||
The <code>html/template</code> package is part of the Go standard library.
|
||||
We can use <code>html/template</code> to keep the HTML in a separate file,
|
||||
allowing us to change the layout of our edit page without modifying the
|
||||
underlying Go code.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
First, we must add <code>html/template</code> to the list of imports. We
|
||||
also won't be using <code>fmt</code> anymore, so we have to remove that.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
import (
|
||||
<b>"html/template"</b>
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
)
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Let's create a template file containing the HTML form.
|
||||
Open a new file named <code>edit.html</code>, and add the following lines:
|
||||
</p>
|
||||
|
||||
{{code "doc/articles/wiki/edit.html"}}
|
||||
|
||||
<p>
|
||||
Modify <code>editHandler</code> to use the template, instead of the hard-coded
|
||||
HTML:
|
||||
</p>
|
||||
|
||||
{{code "doc/articles/wiki/final-noerror.go" `/^func editHandler/` `/^}/`}}
|
||||
|
||||
<p>
|
||||
The function <code>template.ParseFiles</code> will read the contents of
|
||||
<code>edit.html</code> and return a <code>*template.Template</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The method <code>t.Execute</code> executes the template, writing the
|
||||
generated HTML to the <code>http.ResponseWriter</code>.
|
||||
The <code>.Title</code> and <code>.Body</code> dotted identifiers refer to
|
||||
<code>p.Title</code> and <code>p.Body</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Template directives are enclosed in double curly braces.
|
||||
The <code>printf "%s" .Body</code> instruction is a function call
|
||||
that outputs <code>.Body</code> as a string instead of a stream of bytes,
|
||||
the same as a call to <code>fmt.Printf</code>.
|
||||
The <code>html/template</code> package helps guarantee that only safe and
|
||||
correct-looking HTML is generated by template actions. For instance, it
|
||||
automatically escapes any greater than sign (<code>></code>), replacing it
|
||||
with <code>&gt;</code>, to make sure user data does not corrupt the form
|
||||
HTML.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Since we're working with templates now, let's create a template for our
|
||||
<code>viewHandler</code> called <code>view.html</code>:
|
||||
</p>
|
||||
|
||||
{{code "doc/articles/wiki/view.html"}}
|
||||
|
||||
<p>
|
||||
Modify <code>viewHandler</code> accordingly:
|
||||
</p>
|
||||
|
||||
{{code "doc/articles/wiki/final-noerror.go" `/^func viewHandler/` `/^}/`}}
|
||||
|
||||
<p>
|
||||
Notice that we've used almost exactly the same templating code in both
|
||||
handlers. Let's remove this duplication by moving the templating code
|
||||
to its own function:
|
||||
</p>
|
||||
|
||||
{{code "doc/articles/wiki/final-template.go" `/^func renderTemplate/` `/^}/`}}
|
||||
|
||||
<p>
|
||||
And modify the handlers to use that function:
|
||||
</p>
|
||||
|
||||
{{code "doc/articles/wiki/final-template.go" `/^func viewHandler/` `/^}/`}}
|
||||
{{code "doc/articles/wiki/final-template.go" `/^func editHandler/` `/^}/`}}
|
||||
|
||||
<p>
|
||||
If we comment out the registration of our unimplemented save handler in
|
||||
<code>main</code>, we can once again build and test our program.
|
||||
<a href="part3.go">Click here to view the code we've written so far.</a>
|
||||
</p>
|
||||
|
||||
<h2>Handling non-existent pages</h2>
|
||||
|
||||
<p>
|
||||
What if you visit <a href="http://localhost:8080/view/APageThatDoesntExist">
|
||||
<code>/view/APageThatDoesntExist</code></a>? You'll see a page containing
|
||||
HTML. This is because it ignores the error return value from
|
||||
<code>loadPage</code> and continues to try and fill out the template
|
||||
with no data. Instead, if the requested Page doesn't exist, it should
|
||||
redirect the client to the edit Page so the content may be created:
|
||||
</p>
|
||||
|
||||
{{code "doc/articles/wiki/part3-errorhandling.go" `/^func viewHandler/` `/^}/`}}
|
||||
|
||||
<p>
|
||||
The <code>http.Redirect</code> function adds an HTTP status code of
|
||||
<code>http.StatusFound</code> (302) and a <code>Location</code>
|
||||
header to the HTTP response.
|
||||
</p>
|
||||
|
||||
<h2>Saving Pages</h2>
|
||||
|
||||
<p>
|
||||
The function <code>saveHandler</code> will handle the submission of forms
|
||||
located on the edit pages. After uncommenting the related line in
|
||||
<code>main</code>, let's implement the handler:
|
||||
</p>
|
||||
|
||||
{{code "doc/articles/wiki/final-template.go" `/^func saveHandler/` `/^}/`}}
|
||||
|
||||
<p>
|
||||
The page title (provided in the URL) and the form's only field,
|
||||
<code>Body</code>, are stored in a new <code>Page</code>.
|
||||
The <code>save()</code> method is then called to write the data to a file,
|
||||
and the client is redirected to the <code>/view/</code> page.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The value returned by <code>FormValue</code> is of type <code>string</code>.
|
||||
We must convert that value to <code>[]byte</code> before it will fit into
|
||||
the <code>Page</code> struct. We use <code>[]byte(body)</code> to perform
|
||||
the conversion.
|
||||
</p>
|
||||
|
||||
<h2>Error handling</h2>
|
||||
|
||||
<p>
|
||||
There are several places in our program where errors are being ignored. This
|
||||
is bad practice, not least because when an error does occur the program will
|
||||
have unintended behavior. A better solution is to handle the errors and return
|
||||
an error message to the user. That way if something does go wrong, the server
|
||||
will function exactly how we want and the user can be notified.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
First, let's handle the errors in <code>renderTemplate</code>:
|
||||
</p>
|
||||
|
||||
{{code "doc/articles/wiki/final-parsetemplate.go" `/^func renderTemplate/` `/^}/`}}
|
||||
|
||||
<p>
|
||||
The <code>http.Error</code> function sends a specified HTTP response code
|
||||
(in this case "Internal Server Error") and error message.
|
||||
Already the decision to put this in a separate function is paying off.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Now let's fix up <code>saveHandler</code>:
|
||||
</p>
|
||||
|
||||
{{code "doc/articles/wiki/part3-errorhandling.go" `/^func saveHandler/` `/^}/`}}
|
||||
|
||||
<p>
|
||||
Any errors that occur during <code>p.save()</code> will be reported
|
||||
to the user.
|
||||
</p>
|
||||
|
||||
<h2>Template caching</h2>
|
||||
|
||||
<p>
|
||||
There is an inefficiency in this code: <code>renderTemplate</code> calls
|
||||
<code>ParseFiles</code> every time a page is rendered.
|
||||
A better approach would be to call <code>ParseFiles</code> once at program
|
||||
initialization, parsing all templates into a single <code>*Template</code>.
|
||||
Then we can use the
|
||||
<a href="/pkg/html/template/#Template.ExecuteTemplate"><code>ExecuteTemplate</code></a>
|
||||
method to render a specific template.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
First we create a global variable named <code>templates</code>, and initialize
|
||||
it with <code>ParseFiles</code>.
|
||||
</p>
|
||||
|
||||
{{code "doc/articles/wiki/final.go" `/var templates/`}}
|
||||
|
||||
<p>
|
||||
The function <code>template.Must</code> is a convenience wrapper that panics
|
||||
when passed a non-nil <code>error</code> value, and otherwise returns the
|
||||
<code>*Template</code> unaltered. A panic is appropriate here; if the templates
|
||||
can't be loaded the only sensible thing to do is exit the program.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The <code>ParseFiles</code> function takes any number of string arguments that
|
||||
identify our template files, and parses those files into templates that are
|
||||
named after the base file name. If we were to add more templates to our
|
||||
program, we would add their names to the <code>ParseFiles</code> call's
|
||||
arguments.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
We then modify the <code>renderTemplate</code> function to call the
|
||||
<code>templates.ExecuteTemplate</code> method with the name of the appropriate
|
||||
template:
|
||||
</p>
|
||||
|
||||
{{code "doc/articles/wiki/final.go" `/func renderTemplate/` `/^}/`}}
|
||||
|
||||
<p>
|
||||
Note that the template name is the template file name, so we must
|
||||
append <code>".html"</code> to the <code>tmpl</code> argument.
|
||||
</p>
|
||||
|
||||
<h2>Validation</h2>
|
||||
|
||||
<p>
|
||||
As you may have observed, this program has a serious security flaw: a user
|
||||
can supply an arbitrary path to be read/written on the server. To mitigate
|
||||
this, we can write a function to validate the title with a regular expression.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
First, add <code>"regexp"</code> to the <code>import</code> list.
|
||||
Then we can create a global variable to store our validation
|
||||
expression:
|
||||
</p>
|
||||
|
||||
{{code "doc/articles/wiki/final-noclosure.go" `/^var validPath/`}}
|
||||
|
||||
<p>
|
||||
The function <code>regexp.MustCompile</code> will parse and compile the
|
||||
regular expression, and return a <code>regexp.Regexp</code>.
|
||||
<code>MustCompile</code> is distinct from <code>Compile</code> in that it will
|
||||
panic if the expression compilation fails, while <code>Compile</code> returns
|
||||
an <code>error</code> as a second parameter.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Now, let's write a function that uses the <code>validPath</code>
|
||||
expression to validate path and extract the page title:
|
||||
</p>
|
||||
|
||||
{{code "doc/articles/wiki/final-noclosure.go" `/func getTitle/` `/^}/`}}
|
||||
|
||||
<p>
|
||||
If the title is valid, it will be returned along with a <code>nil</code>
|
||||
error value. If the title is invalid, the function will write a
|
||||
"404 Not Found" error to the HTTP connection, and return an error to the
|
||||
handler. To create a new error, we have to import the <code>errors</code>
|
||||
package.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Let's put a call to <code>getTitle</code> in each of the handlers:
|
||||
</p>
|
||||
|
||||
{{code "doc/articles/wiki/final-noclosure.go" `/^func viewHandler/` `/^}/`}}
|
||||
{{code "doc/articles/wiki/final-noclosure.go" `/^func editHandler/` `/^}/`}}
|
||||
{{code "doc/articles/wiki/final-noclosure.go" `/^func saveHandler/` `/^}/`}}
|
||||
|
||||
<h2>Introducing Function Literals and Closures</h2>
|
||||
|
||||
<p>
|
||||
Catching the error condition in each handler introduces a lot of repeated code.
|
||||
What if we could wrap each of the handlers in a function that does this
|
||||
validation and error checking? Go's
|
||||
<a href="/ref/spec#Function_literals">function
|
||||
literals</a> provide a powerful means of abstracting functionality
|
||||
that can help us here.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
First, we re-write the function definition of each of the handlers to accept
|
||||
a title string:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
func viewHandler(w http.ResponseWriter, r *http.Request, title string)
|
||||
func editHandler(w http.ResponseWriter, r *http.Request, title string)
|
||||
func saveHandler(w http.ResponseWriter, r *http.Request, title string)
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Now let's define a wrapper function that <i>takes a function of the above
|
||||
type</i>, and returns a function of type <code>http.HandlerFunc</code>
|
||||
(suitable to be passed to the function <code>http.HandleFunc</code>):
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
func makeHandler(fn func (http.ResponseWriter, *http.Request, string)) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
// Here we will extract the page title from the Request,
|
||||
// and call the provided handler 'fn'
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The returned function is called a closure because it encloses values defined
|
||||
outside of it. In this case, the variable <code>fn</code> (the single argument
|
||||
to <code>makeHandler</code>) is enclosed by the closure. The variable
|
||||
<code>fn</code> will be one of our save, edit, or view handlers.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Now we can take the code from <code>getTitle</code> and use it here
|
||||
(with some minor modifications):
|
||||
</p>
|
||||
|
||||
{{code "doc/articles/wiki/final.go" `/func makeHandler/` `/^}/`}}
|
||||
|
||||
<p>
|
||||
The closure returned by <code>makeHandler</code> is a function that takes
|
||||
an <code>http.ResponseWriter</code> and <code>http.Request</code> (in other
|
||||
words, an <code>http.HandlerFunc</code>).
|
||||
The closure extracts the <code>title</code> from the request path, and
|
||||
validates it with the <code>TitleValidator</code> regexp. If the
|
||||
<code>title</code> is invalid, an error will be written to the
|
||||
<code>ResponseWriter</code> using the <code>http.NotFound</code> function.
|
||||
If the <code>title</code> is valid, the enclosed handler function
|
||||
<code>fn</code> will be called with the <code>ResponseWriter</code>,
|
||||
<code>Request</code>, and <code>title</code> as arguments.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Now we can wrap the handler functions with <code>makeHandler</code> in
|
||||
<code>main</code>, before they are registered with the <code>http</code>
|
||||
package:
|
||||
</p>
|
||||
|
||||
{{code "doc/articles/wiki/final.go" `/func main/` `/^}/`}}
|
||||
|
||||
<p>
|
||||
Finally we remove the calls to <code>getTitle</code> from the handler functions,
|
||||
making them much simpler:
|
||||
</p>
|
||||
|
||||
{{code "doc/articles/wiki/final.go" `/^func viewHandler/` `/^}/`}}
|
||||
{{code "doc/articles/wiki/final.go" `/^func editHandler/` `/^}/`}}
|
||||
{{code "doc/articles/wiki/final.go" `/^func saveHandler/` `/^}/`}}
|
||||
|
||||
<h2>Try it out!</h2>
|
||||
|
||||
<p>
|
||||
<a href="final.go">Click here to view the final code listing.</a>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Recompile the code, and run the app:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
$ go build wiki.go
|
||||
$ ./wiki
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Visiting <a href="http://localhost:8080/view/ANewPage">http://localhost:8080/view/ANewPage</a>
|
||||
should present you with the page edit form. You should then be able to
|
||||
enter some text, click 'Save', and be redirected to the newly created page.
|
||||
</p>
|
||||
|
||||
<h2>Other tasks</h2>
|
||||
|
||||
<p>
|
||||
Here are some simple tasks you might want to tackle on your own:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>Store templates in <code>tmpl/</code> and page data in <code>data/</code>.
|
||||
<li>Add a handler to make the web root redirect to
|
||||
<code>/view/FrontPage</code>.</li>
|
||||
<li>Spruce up the page templates by making them valid HTML and adding some
|
||||
CSS rules.</li>
|
||||
<li>Implement inter-page linking by converting instances of
|
||||
<code>[PageName]</code> to <br>
|
||||
<code><a href="/view/PageName">PageName</a></code>.
|
||||
(hint: you could use <code>regexp.ReplaceAllFunc</code> to do this)
|
||||
</li>
|
||||
</ul>
|
||||
@@ -1,33 +0,0 @@
|
||||
// Copyright 2010 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
type Page struct {
|
||||
Title string
|
||||
Body []byte
|
||||
}
|
||||
|
||||
func (p *Page) save() error {
|
||||
filename := p.Title + ".txt"
|
||||
return ioutil.WriteFile(filename, p.Body, 0600)
|
||||
}
|
||||
|
||||
func loadPage(title string) *Page {
|
||||
filename := title + ".txt"
|
||||
body, _ := ioutil.ReadFile(filename)
|
||||
return &Page{Title: title, Body: body}
|
||||
}
|
||||
|
||||
func main() {
|
||||
p1 := &Page{Title: "TestPage", Body: []byte("This is a sample page.")}
|
||||
p1.save()
|
||||
p2 := loadPage("TestPage")
|
||||
fmt.Println(string(p2.Body))
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
// Copyright 2010 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
type Page struct {
|
||||
Title string
|
||||
Body []byte
|
||||
}
|
||||
|
||||
func (p *Page) save() error {
|
||||
filename := p.Title + ".txt"
|
||||
return ioutil.WriteFile(filename, p.Body, 0600)
|
||||
}
|
||||
|
||||
func loadPage(title string) (*Page, error) {
|
||||
filename := title + ".txt"
|
||||
body, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Page{Title: title, Body: body}, nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
p1 := &Page{Title: "TestPage", Body: []byte("This is a sample Page.")}
|
||||
p1.save()
|
||||
p2, _ := loadPage("TestPage")
|
||||
fmt.Println(string(p2.Body))
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
// Copyright 2010 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type Page struct {
|
||||
Title string
|
||||
Body []byte
|
||||
}
|
||||
|
||||
func (p *Page) save() error {
|
||||
filename := p.Title + ".txt"
|
||||
return ioutil.WriteFile(filename, p.Body, 0600)
|
||||
}
|
||||
|
||||
func loadPage(title string) (*Page, error) {
|
||||
filename := title + ".txt"
|
||||
body, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Page{Title: title, Body: body}, nil
|
||||
}
|
||||
|
||||
func viewHandler(w http.ResponseWriter, r *http.Request) {
|
||||
title := r.URL.Path[len("/view/"):]
|
||||
p, _ := loadPage(title)
|
||||
fmt.Fprintf(w, "<h1>%s</h1><div>%s</div>", p.Title, p.Body)
|
||||
}
|
||||
|
||||
func main() {
|
||||
http.HandleFunc("/view/", viewHandler)
|
||||
http.ListenAndServe(":8080", nil)
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
// Copyright 2010 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"html/template"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type Page struct {
|
||||
Title string
|
||||
Body []byte
|
||||
}
|
||||
|
||||
func (p *Page) save() error {
|
||||
filename := p.Title + ".txt"
|
||||
return ioutil.WriteFile(filename, p.Body, 0600)
|
||||
}
|
||||
|
||||
func loadPage(title string) (*Page, error) {
|
||||
filename := title + ".txt"
|
||||
body, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Page{Title: title, Body: body}, nil
|
||||
}
|
||||
|
||||
func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) {
|
||||
t, _ := template.ParseFiles(tmpl + ".html")
|
||||
t.Execute(w, p)
|
||||
}
|
||||
|
||||
func viewHandler(w http.ResponseWriter, r *http.Request) {
|
||||
title := r.URL.Path[len("/view/"):]
|
||||
p, err := loadPage(title)
|
||||
if err != nil {
|
||||
http.Redirect(w, r, "/edit/"+title, http.StatusFound)
|
||||
return
|
||||
}
|
||||
renderTemplate(w, "view", p)
|
||||
}
|
||||
|
||||
func editHandler(w http.ResponseWriter, r *http.Request) {
|
||||
title := r.URL.Path[len("/edit/"):]
|
||||
p, err := loadPage(title)
|
||||
if err != nil {
|
||||
p = &Page{Title: title}
|
||||
}
|
||||
renderTemplate(w, "edit", p)
|
||||
}
|
||||
|
||||
func saveHandler(w http.ResponseWriter, r *http.Request) {
|
||||
title := r.URL.Path[len("/save/"):]
|
||||
body := r.FormValue("body")
|
||||
p := &Page{Title: title, Body: []byte(body)}
|
||||
err := p.save()
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
http.Redirect(w, r, "/view/"+title, http.StatusFound)
|
||||
}
|
||||
|
||||
func main() {
|
||||
http.HandleFunc("/view/", viewHandler)
|
||||
http.HandleFunc("/edit/", editHandler)
|
||||
http.HandleFunc("/save/", saveHandler)
|
||||
http.ListenAndServe(":8080", nil)
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
// Copyright 2010 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"html/template"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type Page struct {
|
||||
Title string
|
||||
Body []byte
|
||||
}
|
||||
|
||||
func (p *Page) save() error {
|
||||
filename := p.Title + ".txt"
|
||||
return ioutil.WriteFile(filename, p.Body, 0600)
|
||||
}
|
||||
|
||||
func loadPage(title string) (*Page, error) {
|
||||
filename := title + ".txt"
|
||||
body, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Page{Title: title, Body: body}, nil
|
||||
}
|
||||
|
||||
func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) {
|
||||
t, _ := template.ParseFiles(tmpl + ".html")
|
||||
t.Execute(w, p)
|
||||
}
|
||||
|
||||
func viewHandler(w http.ResponseWriter, r *http.Request) {
|
||||
title := r.URL.Path[len("/view/"):]
|
||||
p, _ := loadPage(title)
|
||||
renderTemplate(w, "view", p)
|
||||
}
|
||||
|
||||
func editHandler(w http.ResponseWriter, r *http.Request) {
|
||||
title := r.URL.Path[len("/edit/"):]
|
||||
p, err := loadPage(title)
|
||||
if err != nil {
|
||||
p = &Page{Title: title}
|
||||
}
|
||||
renderTemplate(w, "edit", p)
|
||||
}
|
||||
|
||||
func main() {
|
||||
http.HandleFunc("/view/", viewHandler)
|
||||
http.HandleFunc("/edit/", editHandler)
|
||||
//http.HandleFunc("/save/", saveHandler)
|
||||
http.ListenAndServe(":8080", nil)
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
# Copyright 2010 The Go Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style
|
||||
# license that can be found in the LICENSE file.
|
||||
|
||||
set -e
|
||||
wiki_pid=
|
||||
cleanup() {
|
||||
kill $wiki_pid
|
||||
rm -f test_*.out Test.txt final.bin final-port.txt a.out get.bin
|
||||
}
|
||||
trap cleanup 0 INT
|
||||
|
||||
rm -f get.bin final.bin a.out
|
||||
|
||||
# If called with -all, check that all code snippets compile.
|
||||
if [ "$1" == "-all" ]; then
|
||||
for fn in *.go; do
|
||||
go build -o a.out $fn
|
||||
done
|
||||
fi
|
||||
|
||||
go build -o get.bin get.go
|
||||
go build -o final.bin final.go
|
||||
(./final.bin --addr) &
|
||||
wiki_pid=$!
|
||||
|
||||
l=0
|
||||
while [ ! -f ./final-port.txt ]
|
||||
do
|
||||
l=$(($l+1))
|
||||
if [ "$l" -gt 5 ]
|
||||
then
|
||||
echo "port not available within 5 seconds"
|
||||
exit 1
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
|
||||
addr=$(cat final-port.txt)
|
||||
./get.bin http://$addr/edit/Test > test_edit.out
|
||||
diff -u test_edit.out test_edit.good
|
||||
./get.bin -post=body=some%20content http://$addr/save/Test > test_save.out
|
||||
diff -u test_save.out test_view.good # should be the same as viewing
|
||||
diff -u Test.txt test_Test.txt.good
|
||||
./get.bin http://$addr/view/Test > test_view.out
|
||||
diff -u test_view.out test_view.good
|
||||
|
||||
echo PASS
|
||||
@@ -1,5 +0,0 @@
|
||||
<h1>{{.Title}}</h1>
|
||||
|
||||
<p>[<a href="/edit/{{.Title}}">edit</a>]</p>
|
||||
|
||||
<div>{{printf "%s" .Body}}</div>
|
||||
537
doc/asm.html
@@ -1,537 +0,0 @@
|
||||
<!--{
|
||||
"Title": "A Quick Guide to Go's Assembler",
|
||||
"Path": "/doc/asm"
|
||||
}-->
|
||||
|
||||
<h2 id="introduction">A Quick Guide to Go's Assembler</h2>
|
||||
|
||||
<p>
|
||||
This document is a quick outline of the unusual form of assembly language used by the <code>gc</code>
|
||||
suite of Go compilers (<code>6g</code>, <code>8g</code>, etc.).
|
||||
The document is not comprehensive.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The assembler is based on the input to the Plan 9 assemblers, which is documented in detail
|
||||
<a href="http://plan9.bell-labs.com/sys/doc/asm.html">on the Plan 9 site</a>.
|
||||
If you plan to write assembly language, you should read that document although much of it is Plan 9-specific.
|
||||
This document provides a summary of the syntax and
|
||||
describes the peculiarities that apply when writing assembly code to interact with Go.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The most important thing to know about Go's assembler is that it is not a direct representation of the underlying machine.
|
||||
Some of the details map precisely to the machine, but some do not.
|
||||
This is because the compiler suite (see
|
||||
<a href="http://plan9.bell-labs.com/sys/doc/compiler.html">this description</a>)
|
||||
needs no assembler pass in the usual pipeline.
|
||||
Instead, the compiler emits a kind of incompletely defined instruction set, in binary form, which the linker
|
||||
then completes.
|
||||
In particular, the linker does instruction selection, so when you see an instruction like <code>MOV</code>
|
||||
what the linker actually generates for that operation might not be a move instruction at all, perhaps a clear or load.
|
||||
Or it might correspond exactly to the machine instruction with that name.
|
||||
In general, machine-specific operations tend to appear as themselves, while more general concepts like
|
||||
memory move and subroutine call and return are more abstract.
|
||||
The details vary with architecture, and we apologize for the imprecision; the situation is not well-defined.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The assembler program is a way to generate that intermediate, incompletely defined instruction sequence
|
||||
as input for the linker.
|
||||
If you want to see what the instructions look like in assembly for a given architecture, say amd64, there
|
||||
are many examples in the sources of the standard library, in packages such as
|
||||
<a href="/pkg/runtime/"><code>runtime</code></a> and
|
||||
<a href="/pkg/math/big/"><code>math/big</code></a>.
|
||||
You can also examine what the compiler emits as assembly code:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
$ cat x.go
|
||||
package main
|
||||
|
||||
func main() {
|
||||
println(3)
|
||||
}
|
||||
$ go tool 6g -S x.go # or: go build -gcflags -S x.go
|
||||
|
||||
--- prog list "main" ---
|
||||
0000 (x.go:3) TEXT main+0(SB),$8-0
|
||||
0001 (x.go:3) FUNCDATA $0,gcargs·0+0(SB)
|
||||
0002 (x.go:3) FUNCDATA $1,gclocals·0+0(SB)
|
||||
0003 (x.go:4) MOVQ $3,(SP)
|
||||
0004 (x.go:4) PCDATA $0,$8
|
||||
0005 (x.go:4) CALL ,runtime.printint+0(SB)
|
||||
0006 (x.go:4) PCDATA $0,$-1
|
||||
0007 (x.go:4) PCDATA $0,$0
|
||||
0008 (x.go:4) CALL ,runtime.printnl+0(SB)
|
||||
0009 (x.go:4) PCDATA $0,$-1
|
||||
0010 (x.go:5) RET ,
|
||||
...
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The <code>FUNCDATA</code> and <code>PCDATA</code> directives contain information
|
||||
for use by the garbage collector; they are introduced by the compiler.
|
||||
</p>
|
||||
|
||||
<!-- Commenting out because the feature is gone but it's popular and may come back.
|
||||
|
||||
<p>
|
||||
To see what gets put in the binary after linking, add the <code>-a</code> flag to the linker:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
$ go tool 6l -a x.6 # or: go build -ldflags -a x.go
|
||||
codeblk [0x2000,0x1d059) at offset 0x1000
|
||||
002000 main.main | (3) TEXT main.main+0(SB),$8
|
||||
002000 65488b0c25a0080000 | (3) MOVQ 2208(GS),CX
|
||||
002009 483b21 | (3) CMPQ SP,(CX)
|
||||
00200c 7707 | (3) JHI ,2015
|
||||
00200e e83da20100 | (3) CALL ,1c250+runtime.morestack00
|
||||
002013 ebeb | (3) JMP ,2000
|
||||
002015 4883ec08 | (3) SUBQ $8,SP
|
||||
002019 | (3) FUNCDATA $0,main.gcargs·0+0(SB)
|
||||
002019 | (3) FUNCDATA $1,main.gclocals·0+0(SB)
|
||||
002019 48c7042403000000 | (4) MOVQ $3,(SP)
|
||||
002021 | (4) PCDATA $0,$8
|
||||
002021 e8aad20000 | (4) CALL ,f2d0+runtime.printint
|
||||
002026 | (4) PCDATA $0,$-1
|
||||
002026 | (4) PCDATA $0,$0
|
||||
002026 e865d40000 | (4) CALL ,f490+runtime.printnl
|
||||
00202b | (4) PCDATA $0,$-1
|
||||
00202b 4883c408 | (5) ADDQ $8,SP
|
||||
00202f c3 | (5) RET ,
|
||||
...
|
||||
</pre>
|
||||
|
||||
-->
|
||||
|
||||
<h3 id="symbols">Symbols</h3>
|
||||
|
||||
<p>
|
||||
Some symbols, such as <code>PC</code>, <code>R0</code> and <code>SP</code>, are predeclared and refer to registers.
|
||||
There are two other predeclared symbols, <code>SB</code> (static base) and <code>FP</code> (frame pointer).
|
||||
All user-defined symbols other than jump labels are written as offsets to these pseudo-registers.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The <code>SB</code> pseudo-register can be thought of as the origin of memory, so the symbol <code>foo(SB)</code>
|
||||
is the name <code>foo</code> as an address in memory.
|
||||
This form is used to name global functions and data.
|
||||
Adding <code><></code> to the name, as in <code>foo<>(SB)</code>, makes the name
|
||||
visible only in the current source file, like a top-level <code>static</code> declaration in a C file.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The <code>FP</code> pseudo-register is a virtual frame pointer
|
||||
used to refer to function arguments.
|
||||
The compilers maintain a virtual frame pointer and refer to the arguments on the stack as offsets from that pseudo-register.
|
||||
Thus <code>0(FP)</code> is the first argument to the function,
|
||||
<code>8(FP)</code> is the second (on a 64-bit machine), and so on.
|
||||
When referring to a function argument this way, it is conventional to place the name
|
||||
at the beginning, as in <code>first_arg+0(FP)</code> and <code>second_arg+8(FP)</code>.
|
||||
Some of the assemblers enforce this convention, rejecting plain <code>0(FP)</code> and <code>8(FP)</code>.
|
||||
For assembly functions with Go prototypes, <code>go</code> <code>vet</code> will check that the argument names
|
||||
and offsets match.
|
||||
On 32-bit systems, the low and high 32 bits of a 64-bit value are distinguished by adding
|
||||
a <code>_lo</code> or <code>_hi</code> suffix to the name, as in <code>arg_lo+0(FP)</code> or <code>arg_hi+4(FP)</code>.
|
||||
If a Go prototype does not name its result, the expected assembly name is <code>ret</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The <code>SP</code> pseudo-register is a virtual stack pointer
|
||||
used to refer to frame-local variables and the arguments being
|
||||
prepared for function calls.
|
||||
It points to the top of the local stack frame, so references should use negative offsets
|
||||
in the range [−framesize, 0):
|
||||
<code>x-8(SP)</code>, <code>y-4(SP)</code>, and so on.
|
||||
On architectures with a real register named <code>SP</code>, the name prefix distinguishes
|
||||
references to the virtual stack pointer from references to the architectural <code>SP</code> register.
|
||||
That is, <code>x-8(SP)</code> and <code>-8(SP)</code> are different memory locations:
|
||||
the first refers to the virtual stack pointer pseudo-register, while the second refers to the
|
||||
hardware's <code>SP</code> register.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Instructions, registers, and assembler directives are always in UPPER CASE to remind you
|
||||
that assembly programming is a fraught endeavor.
|
||||
(Exception: the <code>g</code> register renaming on ARM.)
|
||||
</p>
|
||||
|
||||
<p>
|
||||
In Go object files and binaries, the full name of a symbol is the
|
||||
package path followed by a period and the symbol name:
|
||||
<code>fmt.Printf</code> or <code>math/rand.Int</code>.
|
||||
Because the assembler's parser treats period and slash as punctuation,
|
||||
those strings cannot be used directly as identifier names.
|
||||
Instead, the assembler allows the middle dot character U+00B7
|
||||
and the division slash U+2215 in identifiers and rewrites them to
|
||||
plain period and slash.
|
||||
Within an assembler source file, the symbols above are written as
|
||||
<code>fmt·Printf</code> and <code>math∕rand·Int</code>.
|
||||
The assembly listings generated by the compilers when using the <code>-S</code> flag
|
||||
show the period and slash directly instead of the Unicode replacements
|
||||
required by the assemblers.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Most hand-written assembly files do not include the full package path
|
||||
in symbol names, because the linker inserts the package path of the current
|
||||
object file at the beginning of any name starting with a period:
|
||||
in an assembly source file within the math/rand package implementation,
|
||||
the package's Int function can be referred to as <code>·Int</code>.
|
||||
This convention avoids the need to hard-code a package's import path in its
|
||||
own source code, making it easier to move the code from one location to another.
|
||||
</p>
|
||||
|
||||
<h3 id="directives">Directives</h3>
|
||||
|
||||
<p>
|
||||
The assembler uses various directives to bind text and data to symbol names.
|
||||
For example, here is a simple complete function definition. The <code>TEXT</code>
|
||||
directive declares the symbol <code>runtime·profileloop</code> and the instructions
|
||||
that follow form the body of the function.
|
||||
The last instruction in a <code>TEXT</code> block must be some sort of jump, usually a <code>RET</code> (pseudo-)instruction.
|
||||
(If it's not, the linker will append a jump-to-itself instruction; there is no fallthrough in <code>TEXTs</code>.)
|
||||
After the symbol, the arguments are flags (see below)
|
||||
and the frame size, a constant (but see below):
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
TEXT runtime·profileloop(SB),NOSPLIT,$8
|
||||
MOVQ $runtime·profileloop1(SB), CX
|
||||
MOVQ CX, 0(SP)
|
||||
CALL runtime·externalthreadhandler(SB)
|
||||
RET
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
In the general case, the frame size is followed by an argument size, separated by a minus sign.
|
||||
(It's not a subtraction, just idiosyncratic syntax.)
|
||||
The frame size <code>$24-8</code> states that the function has a 24-byte frame
|
||||
and is called with 8 bytes of argument, which live on the caller's frame.
|
||||
If <code>NOSPLIT</code> is not specified for the <code>TEXT</code>,
|
||||
the argument size must be provided.
|
||||
For assembly functions with Go prototypes, <code>go</code> <code>vet</code> will check that the
|
||||
argument size is correct.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Note that the symbol name uses a middle dot to separate the components and is specified as an offset from the
|
||||
static base pseudo-register <code>SB</code>.
|
||||
This function would be called from Go source for package <code>runtime</code> using the
|
||||
simple name <code>profileloop</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Global data symbols are defined by a sequence of initializing
|
||||
<code>DATA</code> directives followed by a <code>GLOBL</code> directive.
|
||||
Each <code>DATA</code> directive initializes a section of the
|
||||
corresponding memory.
|
||||
The memory not explicitly initialized is zeroed.
|
||||
The general form of the <code>DATA</code> directive is
|
||||
|
||||
<pre>
|
||||
DATA symbol+offset(SB)/width, value
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
which initializes the symbol memory at the given offset and width with the given value.
|
||||
The <code>DATA</code> directives for a given symbol must be written with increasing offsets.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The <code>GLOBL</code> directive declares a symbol to be global.
|
||||
The arguments are optional flags and the size of the data being declared as a global,
|
||||
which will have initial value all zeros unless a <code>DATA</code> directive
|
||||
has initialized it.
|
||||
The <code>GLOBL</code> directive must follow any corresponding <code>DATA</code> directives.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
For example,
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
DATA divtab<>+0x00(SB)/4, $0xf4f8fcff
|
||||
DATA divtab<>+0x04(SB)/4, $0xe6eaedf0
|
||||
...
|
||||
DATA divtab<>+0x3c(SB)/4, $0x81828384
|
||||
GLOBL divtab<>(SB), RODATA, $64
|
||||
|
||||
GLOBL runtime·tlsoffset(SB), NOPTR, $4
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
declares and initializes <code>divtab<></code>, a read-only 64-byte table of 4-byte integer values,
|
||||
and declares <code>runtime·tlsoffset</code>, a 4-byte, implicitly zeroed variable that
|
||||
contains no pointers.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
There may be one or two arguments to the directives.
|
||||
If there are two, the first is a bit mask of flags,
|
||||
which can be written as numeric expressions, added or or-ed together,
|
||||
or can be set symbolically for easier absorption by a human.
|
||||
Their values, defined in the standard <code>#include</code> file <code>textflag.h</code>, are:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<code>NOPROF</code> = 1
|
||||
<br>
|
||||
(For <code>TEXT</code> items.)
|
||||
Don't profile the marked function. This flag is deprecated.
|
||||
</li>
|
||||
<li>
|
||||
<code>DUPOK</code> = 2
|
||||
<br>
|
||||
It is legal to have multiple instances of this symbol in a single binary.
|
||||
The linker will choose one of the duplicates to use.
|
||||
</li>
|
||||
<li>
|
||||
<code>NOSPLIT</code> = 4
|
||||
<br>
|
||||
(For <code>TEXT</code> items.)
|
||||
Don't insert the preamble to check if the stack must be split.
|
||||
The frame for the routine, plus anything it calls, must fit in the
|
||||
spare space at the top of the stack segment.
|
||||
Used to protect routines such as the stack splitting code itself.
|
||||
</li>
|
||||
<li>
|
||||
<code>RODATA</code> = 8
|
||||
<br>
|
||||
(For <code>DATA</code> and <code>GLOBL</code> items.)
|
||||
Put this data in a read-only section.
|
||||
</li>
|
||||
<li>
|
||||
<code>NOPTR</code> = 16
|
||||
<br>
|
||||
(For <code>DATA</code> and <code>GLOBL</code> items.)
|
||||
This data contains no pointers and therefore does not need to be
|
||||
scanned by the garbage collector.
|
||||
</li>
|
||||
<li>
|
||||
<code>WRAPPER</code> = 32
|
||||
<br>
|
||||
(For <code>TEXT</code> items.)
|
||||
This is a wrapper function and should not count as disabling <code>recover</code>.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="runtime">Runtime Coordination</h3>
|
||||
|
||||
<p>
|
||||
For garbage collection to run correctly, the runtime must know the
|
||||
location of pointers in all global data and in most stack frames.
|
||||
The Go compiler emits this information when compiling Go source files,
|
||||
but assembly programs must define it explicitly.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
A data symbol marked with the <code>NOPTR</code> flag (see above)
|
||||
is treated as containing no pointers to runtime-allocated data.
|
||||
A data symbol with the <code>RODATA</code> flag
|
||||
is allocated in read-only memory and is therefore treated
|
||||
as implicitly marked <code>NOPTR</code>.
|
||||
A data symbol with a total size smaller than a pointer
|
||||
is also treated as implicitly marked <code>NOPTR</code>.
|
||||
It is not possible to define a symbol containing pointers in an assembly source file;
|
||||
such a symbol must be defined in a Go source file instead.
|
||||
Assembly source can still refer to the symbol by name
|
||||
even without <code>DATA</code> and <code>GLOBL</code> directives.
|
||||
A good general rule of thumb is to define all non-<code>RODATA</code>
|
||||
symbols in Go instead of in assembly.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Each function also needs annotations giving the location of
|
||||
live pointers in its arguments, results, and local stack frame.
|
||||
For an assembly function with no pointer results and
|
||||
either no local stack frame or no function calls,
|
||||
the only requirement is to define a Go prototype for the function
|
||||
in a Go source file in the same package.
|
||||
For more complex situations, explicit annotation is needed.
|
||||
These annotations use pseudo-instructions defined in the standard
|
||||
<code>#include</code> file <code>funcdata.h</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If a function has no arguments and no results,
|
||||
the pointer information can be omitted.
|
||||
This is indicated by an argument size annotation of <code>$<i>n</i>-0</code>
|
||||
on the <code>TEXT</code> instruction.
|
||||
Otherwise, pointer information must be provided by
|
||||
a Go prototype for the function in a Go source file,
|
||||
even for assembly functions not called directly from Go.
|
||||
(The prototype will also let <code>go</code> <code>vet</code> check the argument references.)
|
||||
At the start of the function, the arguments are assumed
|
||||
to be initialized but the results are assumed uninitialized.
|
||||
If the results will hold live pointers during a call instruction,
|
||||
the function should start by zeroing the results and then
|
||||
executing the pseudo-instruction <code>GO_RESULTS_INITIALIZED</code>.
|
||||
This instruction records that the results are now initialized
|
||||
and should be scanned during stack movement and garbage collection.
|
||||
It is typically easier to arrange that assembly functions do not
|
||||
return pointers or do not contain call instructions;
|
||||
no assembly functions in the standard library use
|
||||
<code>GO_RESULTS_INITIALIZED</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If a function has no local stack frame,
|
||||
the pointer information can be omitted.
|
||||
This is indicated by a local frame size annotation of <code>$0-<i>n</i></code>
|
||||
on the <code>TEXT</code> instruction.
|
||||
The pointer information can also be omitted if the
|
||||
function contains no call instructions.
|
||||
Otherwise, the local stack frame must not contain pointers,
|
||||
and the assembly must confirm this fact by executing the
|
||||
pseudo-instruction <code>NO_LOCAL_POINTERS</code>.
|
||||
Because stack resizing is implemented by moving the stack,
|
||||
the stack pointer may change during any function call:
|
||||
even pointers to stack data must not be kept in local variables.
|
||||
</p>
|
||||
|
||||
<h2 id="architectures">Architecture-specific details</h2>
|
||||
|
||||
<p>
|
||||
It is impractical to list all the instructions and other details for each machine.
|
||||
To see what instructions are defined for a given machine, say 32-bit Intel x86,
|
||||
look in the top-level header file for the corresponding linker, in this case <code>8l</code>.
|
||||
That is, the file <code>$GOROOT/src/cmd/8l/8.out.h</code> contains a C enumeration, called <code>as</code>,
|
||||
of the instructions and their spellings as known to the assembler and linker for that architecture.
|
||||
In that file you'll find a declaration that begins
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
enum as
|
||||
{
|
||||
AXXX,
|
||||
AAAA,
|
||||
AAAD,
|
||||
AAAM,
|
||||
AAAS,
|
||||
AADCB,
|
||||
...
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Each instruction begins with a initial capital <code>A</code> in this list, so <code>AADCB</code>
|
||||
represents the <code>ADCB</code> (add carry byte) instruction.
|
||||
The enumeration is in alphabetical order, plus some late additions (<code>AXXX</code> occupies
|
||||
the zero slot as an invalid instruction).
|
||||
The sequence has nothing to do with the actual encoding of the machine instructions.
|
||||
Again, the linker takes care of that detail.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
One detail evident in the examples from the previous sections is that data in the instructions flows from left to right:
|
||||
<code>MOVQ</code> <code>$0,</code> <code>CX</code> clears <code>CX</code>.
|
||||
This convention applies even on architectures where the usual mode is the opposite direction.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Here follows some descriptions of key Go-specific details for the supported architectures.
|
||||
</p>
|
||||
|
||||
<h3 id="x86">32-bit Intel 386</h3>
|
||||
|
||||
<p>
|
||||
The runtime pointer to the <code>g</code> structure is maintained
|
||||
through the value of an otherwise unused (as far as Go is concerned) register in the MMU.
|
||||
A OS-dependent macro <code>get_tls</code> is defined for the assembler if the source includes
|
||||
an architecture-dependent header file, like this:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
#include "zasm_GOOS_GOARCH.h"
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Within the runtime, the <code>get_tls</code> macro loads its argument register
|
||||
with a pointer to the <code>g</code> pointer, and the <code>g</code> struct
|
||||
contains the <code>m</code> pointer.
|
||||
The sequence to load <code>g</code> and <code>m</code> using <code>CX</code> looks like this:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
get_tls(CX)
|
||||
MOVL g(CX), AX // Move g into AX.
|
||||
MOVL g_m(AX), BX // Move g->m into BX.
|
||||
</pre>
|
||||
|
||||
<h3 id="amd64">64-bit Intel 386 (a.k.a. amd64)</h3>
|
||||
|
||||
<p>
|
||||
The assembly code to access the <code>m</code> and <code>g</code>
|
||||
pointers is the same as on the 386, except it uses <code>MOVQ</code> rather than
|
||||
<code>MOVL</code>:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
get_tls(CX)
|
||||
MOVQ g(CX), AX // Move g into AX.
|
||||
MOVQ g_m(AX), BX // Move g->m into BX.
|
||||
</pre>
|
||||
|
||||
<h3 id="arm">ARM</h3>
|
||||
|
||||
<p>
|
||||
The registers <code>R10</code> and <code>R11</code>
|
||||
are reserved by the compiler and linker.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<code>R10</code> points to the <code>g</code> (goroutine) structure.
|
||||
Within assembler source code, this pointer must be referred to as <code>g</code>;
|
||||
the name <code>R10</code> is not recognized.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
To make it easier for people and compilers to write assembly, the ARM linker
|
||||
allows general addressing forms and pseudo-operations like <code>DIV</code> or <code>MOD</code>
|
||||
that may not be expressible using a single hardware instruction.
|
||||
It implements these forms as multiple instructions, often using the <code>R11</code> register
|
||||
to hold temporary values.
|
||||
Hand-written assembly can use <code>R11</code>, but doing so requires
|
||||
being sure that the linker is not also using it to implement any of the other
|
||||
instructions in the function.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
When defining a <code>TEXT</code>, specifying frame size <code>$-4</code>
|
||||
tells the linker that this is a leaf function that does not need to save <code>LR</code> on entry.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The name <code>SP</code> always refers to the virtual stack pointer described earlier.
|
||||
For the hardware register, use <code>R13</code>.
|
||||
</p>
|
||||
|
||||
<h3 id="unsupported_opcodes">Unsupported opcodes</h3>
|
||||
|
||||
<p>
|
||||
The assemblers are designed to support the compiler so not all hardware instructions
|
||||
are defined for all architectures: if the compiler doesn't generate it, it might not be there.
|
||||
If you need to use a missing instruction, there are two ways to proceed.
|
||||
One is to update the assembler to support that instruction, which is straightforward
|
||||
but only worthwhile if it's likely the instruction will be used again.
|
||||
Instead, for simple one-off cases, it's possible to use the <code>BYTE</code>
|
||||
and <code>WORD</code> directives
|
||||
to lay down explicit data into the instruction stream within a <code>TEXT</code>.
|
||||
Here's how the 386 runtime defines the 64-bit atomic load function.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
// uint64 atomicload64(uint64 volatile* addr);
|
||||
// so actually
|
||||
// void atomicload64(uint64 *res, uint64 volatile *addr);
|
||||
TEXT runtime·atomicload64(SB), NOSPLIT, $0-8
|
||||
MOVL ptr+0(FP), AX
|
||||
LEAL ret_lo+4(FP), BX
|
||||
BYTE $0x0f; BYTE $0x6f; BYTE $0x00 // MOVQ (%EAX), %MM0
|
||||
BYTE $0x0f; BYTE $0x7f; BYTE $0x03 // MOVQ %MM0, 0(%EBX)
|
||||
BYTE $0x0F; BYTE $0x77 // EMMS
|
||||
RET
|
||||
</pre>
|
||||
BIN
doc/button_background.png
Normal file
|
After Width: | Height: | Size: 126 B |
109
doc/cmd.html
@@ -1,109 +0,0 @@
|
||||
<!--{
|
||||
"Title": "Command Documentation",
|
||||
"Path": "/doc/cmd"
|
||||
}-->
|
||||
|
||||
<p>
|
||||
There is a suite of programs to build and process Go source code.
|
||||
Instead of being run directly, programs in the suite are usually invoked
|
||||
by the <a href="/cmd/go/">go</a> program.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The most common way to run these programs is as a subcommand of the go program,
|
||||
for instance as <code>go fmt</code>. Run like this, the command operates on
|
||||
complete packages of Go source code, with the go program invoking the
|
||||
underlying binary with arguments appropriate to package-level processing.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The programs can also be run as stand-alone binaries, with unmodified arguments,
|
||||
using the go <code>tool</code> subcommand, such as <code>go tool vet</code>.
|
||||
This style of invocation allows, for instance, checking a single source file
|
||||
rather than an entire package: <code>go tool vet myprogram.go</code> as
|
||||
compared to <code>go vet mypackage</code>.
|
||||
Some of the commands, such as <code>yacc</code>, are accessible only through
|
||||
the go <code>tool</code> subcommand.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Finally the <code>fmt</code> and <code>godoc</code> commands are installed
|
||||
as regular binaries called <code>gofmt</code> and <code>godoc</code> because
|
||||
they are so often referenced.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Click on the links for more documentation, invocation methods, and usage details.
|
||||
</p>
|
||||
|
||||
<table class="dir">
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th> </th>
|
||||
<th>Synopsis</th>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><a href="/cmd/go/">go</a></td>
|
||||
<td> </td>
|
||||
<td>
|
||||
The <code>go</code> program manages Go source code and runs the other
|
||||
commands listed here.
|
||||
See the command docs for usage
|
||||
details.
|
||||
<br><br>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><a href="/cmd/cgo/">cgo</a></td>
|
||||
<td> </td>
|
||||
<td>Cgo enables the creation of Go packages that call C code.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><a href="//godoc.org/code.google.com/p/go.tools/cmd/cover/">cover</a></td>
|
||||
<td> </td>
|
||||
<td>Cover is a program for creating and analyzing the coverage profiles
|
||||
generated by <code>"go test -coverprofile"</code>.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><a href="/cmd/fix/">fix</a></td>
|
||||
<td> </td>
|
||||
<td>Fix finds Go programs that use old features of the language and libraries
|
||||
and rewrites them to use newer ones.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><a href="/cmd/go/">fmt</a></td>
|
||||
<td> </td>
|
||||
<td>Fmt formats Go packages, it is also available as an independent <a href="/cmd/gofmt/">
|
||||
gofmt</a> command with more general options.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><a href="//godoc.org/code.google.com/p/go.tools/cmd/godoc/">godoc</a></td>
|
||||
<td> </td>
|
||||
<td>Godoc extracts and generates documentation for Go packages.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><a href="//godoc.org/code.google.com/p/go.tools/cmd/vet/">vet</a></td>
|
||||
<td> </td>
|
||||
<td>Vet examines Go source code and reports suspicious constructs, such as Printf
|
||||
calls whose arguments do not align with the format string.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><a href="/cmd/yacc/">yacc</a></td>
|
||||
<td> </td>
|
||||
<td>Yacc is a version of yacc that generates parsers implemented in Go.</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
|
||||
<p>
|
||||
This is an abridged list. See the <a href="/cmd/">full command reference</a>
|
||||
for documentation of the compilers and more.
|
||||
</p>
|
||||
820
doc/code.html
@@ -1,622 +1,368 @@
|
||||
<!--{
|
||||
"Title": "How to Write Go Code"
|
||||
}-->
|
||||
<!-- How to Write Go Code -->
|
||||
|
||||
<h2 id="Introduction">Introduction</h2>
|
||||
|
||||
<p>
|
||||
This document demonstrates the development of a simple Go package and
|
||||
introduces the <a href="/cmd/go/">go tool</a>, the standard way to fetch,
|
||||
build, and install Go packages and commands.
|
||||
This document explains how to write a new package
|
||||
and how to test code.
|
||||
It assumes you have installed Go using the
|
||||
<a href="install.html">installation instructions</a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The <code>go</code> tool requires you to organize your code in a specific
|
||||
way. Please read this document carefully.
|
||||
It explains the simplest way to get up and running with your Go installation.
|
||||
Before embarking on a change to an existing
|
||||
package or the creation of a new package,
|
||||
be sure to send mail to the
|
||||
<a href="http://groups.google.com/group/golang-nuts">mailing list</a>
|
||||
to let people know what you are thinking of doing.
|
||||
Doing so helps avoid duplication of effort and
|
||||
enables discussions about design before any code
|
||||
has been written.
|
||||
</p>
|
||||
|
||||
<h2 id="Community_resources">Community resources</h2>
|
||||
|
||||
<p>
|
||||
For real-time help, there may be users or developers on
|
||||
<code>#go-nuts</code> on the <a href="http://freenode.net/">Freenode</a> IRC server.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
A similar explanation is available as a
|
||||
<a href="//www.youtube.com/watch?v=XCsL89YtqCs">screencast</a>.
|
||||
</p>
|
||||
|
||||
|
||||
<h2 id="Organization">Code organization</h2>
|
||||
|
||||
<h3 id="Workspaces">Workspaces</h3>
|
||||
|
||||
<p>
|
||||
The <code>go</code> tool is designed to work with open source code maintained
|
||||
in public repositories. Although you don't need to publish your code, the model
|
||||
for how the environment is set up works the same whether you do or not.
|
||||
The official mailing list for discussion of the Go language is
|
||||
<a href="http://groups.google.com/group/golang-nuts">Go Nuts</a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Go code must be kept inside a <i>workspace</i>.
|
||||
A workspace is a directory hierarchy with three directories at its root:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li><code>src</code> contains Go source files organized into packages (one package per directory),
|
||||
<li><code>pkg</code> contains package objects, and
|
||||
<li><code>bin</code> contains executable commands.
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
The <code>go</code> tool builds source packages and installs the resulting
|
||||
binaries to the <code>pkg</code> and <code>bin</code> directories.
|
||||
Bugs can be reported using the <a href="http://code.google.com/p/go/issues/list">Go issue tracker</a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The <code>src</code> subdirectory typically contains multiple version control
|
||||
repositories (such as for Git or Mercurial) that track the development of one
|
||||
or more source packages.
|
||||
For those who wish to keep up with development,
|
||||
there is another mailing list, <a href="http://groups.google.com/group/golang-checkins">golang-checkins</a>,
|
||||
that receives a message summarizing each checkin to the Go repository.
|
||||
</p>
|
||||
|
||||
|
||||
<h2 id="New_package">Creating a new package</h2>
|
||||
|
||||
<p>
|
||||
To give you an idea of how a workspace looks in practice, here's an example:
|
||||
The source code for the package with import path
|
||||
<code>x/y</code> is, by convention, kept in the
|
||||
directory <code>$GOROOT/src/pkg/x/y</code>.
|
||||
</p>
|
||||
|
||||
<h3>Makefile</h3>
|
||||
|
||||
<p>
|
||||
It would be nice to have Go-specific tools that
|
||||
inspect the source files to determine what to build and in
|
||||
what order, but for now, Go uses GNU <code>make</code>.
|
||||
Thus, the first file to create in a new package directory is
|
||||
usually the <code>Makefile</code>.
|
||||
The basic form used in the Go source tree
|
||||
is illustrated by <a href="../src/pkg/container/vector/Makefile"><code>src/pkg/container/vector/Makefile</code></a>:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
bin/
|
||||
streak # command executable
|
||||
todo # command executable
|
||||
pkg/
|
||||
linux_amd64/
|
||||
code.google.com/p/goauth2/
|
||||
oauth.a # package object
|
||||
github.com/nf/todo/
|
||||
task.a # package object
|
||||
src/
|
||||
code.google.com/p/goauth2/
|
||||
.hg/ # mercurial repository metadata
|
||||
oauth/
|
||||
oauth.go # package source
|
||||
oauth_test.go # test source
|
||||
github.com/nf/
|
||||
streak/
|
||||
.git/ # git repository metadata
|
||||
oauth.go # command source
|
||||
streak.go # command source
|
||||
todo/
|
||||
.git/ # git repository metadata
|
||||
task/
|
||||
task.go # package source
|
||||
todo.go # command source
|
||||
include ../../../Make.inc
|
||||
|
||||
TARG=container/vector
|
||||
GOFILES=\
|
||||
intvector.go\
|
||||
stringvector.go\
|
||||
vector.go\
|
||||
|
||||
include ../../../Make.pkg
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
This workspace contains three repositories (<code>goauth2</code>,
|
||||
<code>streak</code>, and <code>todo</code>) comprising two commands
|
||||
(<code>streak</code> and <code>todo</code>) and two libraries
|
||||
(<code>oauth</code> and <code>task</code>).
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Commands and libraries are built from different kinds of source packages.
|
||||
We will discuss the distinction <a href="#PackageNames">later</a>.
|
||||
</p>
|
||||
|
||||
|
||||
<h3 id="GOPATH">The <code>GOPATH</code> environment variable</h3>
|
||||
|
||||
<p>
|
||||
The <code>GOPATH</code> environment variable specifies the location of your
|
||||
workspace. It is likely the only environment variable you'll need to set
|
||||
when developing Go code.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
To get started, create a workspace directory and set <code>GOPATH</code>
|
||||
accordingly. Your workspace can be located wherever you like, but we'll use
|
||||
<code>$HOME/go</code> in this document. Note that this must <b>not</b> be the
|
||||
same path as your Go installation.
|
||||
Outside the Go source tree (for personal packages), the standard form is
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
$ <b>mkdir $HOME/go</b>
|
||||
$ <b>export GOPATH=$HOME/go</b>
|
||||
include $(GOROOT)/src/Make.inc
|
||||
|
||||
TARG=mypackage
|
||||
GOFILES=\
|
||||
my1.go\
|
||||
my2.go\
|
||||
|
||||
include $(GOROOT)/src/Make.pkg
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
For convenience, add the workspace's <code>bin</code> subdirectory
|
||||
to your <code>PATH</code>:
|
||||
The first and last lines <code>include</code> standard definitions and rules.
|
||||
Packages maintained in the standard Go tree use a relative path (instead of
|
||||
<code>$(GOROOT)/src</code>) so that <code>make</code> will work correctly
|
||||
even if <code>$(GOROOT)</code> contains spaces.
|
||||
This makes it easy for programmers to try Go.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If you have not set <code>$GOROOT</code> in your environment,
|
||||
you must run <code>gomake</code> to use this form of makefile.
|
||||
<code>Gomake</code> also takes care to invoke GNU Make
|
||||
even on systems where it is installed as <code>gmake</code>
|
||||
rather than <code>make</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<code>TARG</code> is the target install path for the package,
|
||||
the string that clients will use to import it.
|
||||
Inside the Go tree, this string should be the same as the directory
|
||||
in which the <code>Makefile</code> appears, with the
|
||||
<code>$GOROOT/src/pkg/</code> prefix removed.
|
||||
Outside the Go tree, you can use any <code>TARG</code> you
|
||||
want that doesn't conflict with the standard Go package names.
|
||||
A common convention is to use an identifying top-level name
|
||||
to group your packages: <code>myname/tree</code>, <code>myname/filter</code>, etc.
|
||||
Note that even if you keep your package source outside the
|
||||
Go tree, running <code>make install</code> installs your
|
||||
package binaries in the standard location—<code>$GOROOT/pkg</code>—to
|
||||
make it easy to find them.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<code>GOFILES</code> is a list of source files to compile to
|
||||
create the package. The trailing <code>\</code> characters
|
||||
allow the list to be split onto multiple lines
|
||||
for easy sorting.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If you create a new package directory in the Go tree, add it to the list in
|
||||
<code>$GOROOT/src/pkg/Makefile</code> so that it
|
||||
is included in the standard build. Then run:
|
||||
<pre>
|
||||
$ <b>export PATH=$PATH:$GOPATH/bin</b>
|
||||
cd $GOROOT/src/pkg
|
||||
./deps.bash
|
||||
</pre>
|
||||
|
||||
|
||||
<h3 id="PackagePaths">Package paths</h3>
|
||||
|
||||
<p>
|
||||
The packages from the standard library are given short paths such as
|
||||
<code>"fmt"</code> and <code>"net/http"</code>.
|
||||
For your own packages, you must choose a base path that is unlikely to
|
||||
collide with future additions to the standard library or other external
|
||||
libraries.
|
||||
to update the dependency file <code>Make.deps</code>.
|
||||
(This happens automatically each time you run <code>all.bash</code>
|
||||
or <code>make.bash</code>.)
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If you keep your code in a source repository somewhere, then you should use the
|
||||
root of that source repository as your base path.
|
||||
For instance, if you have a <a href="https://github.com/">GitHub</a> account at
|
||||
<code>github.com/user</code>, that should be your base path.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Note that you don't need to publish your code to a remote repository before you
|
||||
can build it. It's just a good habit to organize your code as if you will
|
||||
publish it someday. In practice you can choose any arbitrary path name,
|
||||
as long as it is unique to the standard library and greater Go ecosystem.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
We'll use <code>github.com/user</code> as our base path. Create a directory
|
||||
inside your workspace in which to keep source code:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
$ <b>mkdir -p $GOPATH/src/github.com/user</b>
|
||||
</pre>
|
||||
|
||||
|
||||
<h3 id="Command">Your first program</h3>
|
||||
|
||||
<p>
|
||||
To compile and run a simple program, first choose a package path (we'll use
|
||||
<code>github.com/user/hello</code>) and create a corresponding package directory
|
||||
inside your workspace:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
$ <b>mkdir $GOPATH/src/github.com/user/hello</b>
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Next, create a file named <code>hello.go</code> inside that directory,
|
||||
containing the following Go code.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
fmt.Printf("Hello, world.\n")
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Now you can build and install that program with the <code>go</code> tool:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
$ <b>go install github.com/user/hello</b>
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Note that you can run this command from anywhere on your system. The
|
||||
<code>go</code> tool finds the source code by looking for the
|
||||
<code>github.com/user/hello</code> package inside the workspace specified by
|
||||
<code>GOPATH</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
You can also omit the package path if you run <code>go install</code> from the
|
||||
package directory:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
$ <b>cd $GOPATH/src/github.com/user/hello</b>
|
||||
$ <b>go install</b>
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
This command builds the <code>hello</code> command, producing an executable
|
||||
binary. It then installs that binary to the workspace's <code>bin</code>
|
||||
directory as <code>hello</code> (or, under Windows, <code>hello.exe</code>).
|
||||
In our example, that will be <code>$GOPATH/bin/hello</code>, which is
|
||||
<code>$HOME/go/bin/hello</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The <code>go</code> tool will only print output when an error occurs, so if
|
||||
these commands produce no output they have executed successfully.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
You can now run the program by typing its full path at the command line:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
$ <b>$GOPATH/bin/hello</b>
|
||||
Hello, world.
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Or, as you have added <code>$GOPATH/bin</code> to your <code>PATH</code>,
|
||||
just type the binary name:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
$ <b>hello</b>
|
||||
Hello, world.
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
If you're using a source control system, now would be a good time to initialize
|
||||
a repository, add the files, and commit your first change. Again, this step is
|
||||
optional: you do not need to use source control to write Go code.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
$ <b>cd $GOPATH/src/github.com/user/hello</b>
|
||||
$ <b>git init</b>
|
||||
Initialized empty Git repository in /home/user/go/src/github.com/user/hello/.git/
|
||||
$ <b>git add hello.go</b>
|
||||
$ <b>git commit -m "initial commit"</b>
|
||||
[master (root-commit) 0b4507d] initial commit
|
||||
1 file changed, 1 insertion(+)
|
||||
create mode 100644 hello.go
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Pushing the code to a remote repository is left as an exercise for the reader.
|
||||
If you change the imports of an existing package,
|
||||
you do not need to edit <code>$GOROOT/src/pkg/Makefile</code>
|
||||
but you will still need to run <code>deps.bash</code> as above.
|
||||
</p>
|
||||
|
||||
|
||||
<h3 id="Library">Your first library</h3>
|
||||
<h3>Go source files</h3>
|
||||
|
||||
<p>
|
||||
Let's write a library and use it from the <code>hello</code> program.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Again, the first step is to choose a package path (we'll use
|
||||
<code>github.com/user/newmath</code>) and create the package directory:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
$ <b>mkdir $GOPATH/src/github.com/user/newmath</b>
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Next, create a file named <code>sqrt.go</code> in that directory with the
|
||||
following contents.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
// Package newmath is a trivial example package.
|
||||
package newmath
|
||||
|
||||
// Sqrt returns an approximation to the square root of x.
|
||||
func Sqrt(x float64) float64 {
|
||||
z := 1.0
|
||||
for i := 0; i < 1000; i++ {
|
||||
z -= (z*z - x) / (2 * z)
|
||||
}
|
||||
return z
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Now, test that the package compiles with <code>go build</code>:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
$ <b>go build github.com/user/newmath</b>
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Or, if you are working in the package's source directory, just:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
$ <b>go build</b>
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
This won't produce an output file. To do that, you must use <code>go
|
||||
install</code>, which places the package object inside the <code>pkg</code>
|
||||
directory of the workspace.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
After confirming that the <code>newmath</code> package builds,
|
||||
modify your original <code>hello.go</code> (which is in
|
||||
<code>$GOPATH/src/github.com/user/hello</code>) to use it:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
<b>"github.com/user/newmath"</b>
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Printf("Hello, world. <b>Sqrt(2) = %v\n", newmath.Sqrt(2)</b>)
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Whenever the <code>go</code> tool installs a package or binary, it also
|
||||
installs whatever dependencies it has. So when you install the <code>hello</code>
|
||||
program
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
$ <b>go install github.com/user/hello</b>
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
the <code>newmath</code> package will be installed as well, automatically.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Running the new version of the program, you should see some numerical output:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
$ <b>hello</b>
|
||||
Hello, world. Sqrt(2) = 1.414213562373095
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
After the steps above, your workspace should look like this:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
bin/
|
||||
hello # command executable
|
||||
pkg/
|
||||
linux_amd64/ # this will reflect your OS and architecture
|
||||
github.com/user/
|
||||
newmath.a # package object
|
||||
src/
|
||||
github.com/user/
|
||||
hello/
|
||||
hello.go # command source
|
||||
newmath/
|
||||
sqrt.go # package source
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Note that <code>go install</code> placed the <code>newmath.a</code> object in a
|
||||
directory inside <code>pkg/linux_amd64</code> that mirrors its source
|
||||
directory.
|
||||
This is so that future invocations of the <code>go</code> tool can find the
|
||||
package object and avoid recompiling the package unnecessarily.
|
||||
The <code>linux_amd64</code> part is there to aid in cross-compilation,
|
||||
and will reflect the operating system and architecture of your system.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Go command executables are statically linked; the package objects need not
|
||||
be present to run Go programs.
|
||||
</p>
|
||||
|
||||
|
||||
<h3 id="PackageNames">Package names</h3>
|
||||
|
||||
<p>
|
||||
The first statement in a Go source file must be
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
package <i>name</i>
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
where <code><i>name</i></code> is the package's default name for imports.
|
||||
The first statement in each of the source files listed in the <code>Makefile</code>
|
||||
should be <code>package <i>name</i></code>, where <code><i>name</i></code>
|
||||
is the package's default name for imports.
|
||||
(All files in a package must use the same <code><i>name</i></code>.)
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Go's convention is that the package name is the last element of the
|
||||
import path: the package imported as "<code>crypto/rot13</code>"
|
||||
import path: the package imported as <code>"crypto/rot13"</code>
|
||||
should be named <code>rot13</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Executable commands must always use <code>package main</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
There is no requirement that package names be unique
|
||||
across all packages linked into a single binary,
|
||||
only that the import paths (their full file names) be unique.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
See <a href="/doc/effective_go.html#names">Effective Go</a> to learn more about
|
||||
Go's naming conventions.
|
||||
Go compiles all the source files in a package at once, so one file
|
||||
can refer to constants, variables, types, and functions in another
|
||||
file without special arrangement or declarations.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Writing clean, idiomatic Go code is beyond the scope of this document.
|
||||
<a href="effective_go.html">Effective Go</a> is an introduction to
|
||||
that topic.
|
||||
</p>
|
||||
|
||||
<h2 id="Building_programs">Building programs</h2>
|
||||
<p>To build a Go program with gomake, create a Makefile alongside your program's
|
||||
source files. It should be similar to the example above, but include
|
||||
<code>Make.cmd</code> instead of <code>Make.pkg</code>:
|
||||
|
||||
<pre>
|
||||
include $(GOROOT)/src/Make.inc
|
||||
|
||||
TARG=helloworld
|
||||
GOFILES=\
|
||||
helloworld.go\
|
||||
|
||||
include $(GOROOT)/src/Make.cmd
|
||||
</pre>
|
||||
|
||||
<p>Running <code>gomake</code> will compile <code>helloworld.go</code>
|
||||
and produce an executable named <code>helloworld</code> in the current
|
||||
directory.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Running <code>gomake install</code> will build <code>helloworld</code> if
|
||||
necessary and copy it to the <code>$GOBIN</code> directory
|
||||
(<code>$GOROOT/bin/</code> is the default).
|
||||
</p>
|
||||
|
||||
<h2 id="Testing">Testing</h2>
|
||||
|
||||
<p>
|
||||
Go has a lightweight test framework composed of the <code>go test</code>
|
||||
command and the <code>testing</code> package.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Go has a lightweight test framework known as <code>gotest</code>.
|
||||
You write a test by creating a file with a name ending in <code>_test.go</code>
|
||||
that contains functions named <code>TestXXX</code> with signature
|
||||
<code>func (t *testing.T)</code>.
|
||||
that contains functions named <code>TestXXX</code> with signature <code>func (t *testing.T)</code>.
|
||||
The test framework runs each such function;
|
||||
if the function calls a failure function such as <code>t.Error</code> or
|
||||
<code>t.Fail</code>, the test is considered to have failed.
|
||||
if the function calls a failure function such as <code>t.Error</code> or <code>t.Fail</code>, the test is considered to have failed.
|
||||
The <a href="/cmd/gotest/">gotest command documentation</a>
|
||||
and the <a href="/pkg/testing/">testing package documentation</a> give more detail.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Add a test to the <code>newmath</code> package by creating the file
|
||||
<code>$GOPATH/src/github.com/user/newmath/sqrt_test.go</code> containing the
|
||||
following Go code.
|
||||
The <code>*_test.go</code> files should not be listed in the <code>Makefile</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
To run the test, run either <code>make test</code> or <code>gotest</code>
|
||||
(they are equivalent).
|
||||
To run only the tests in a single test file, for instance <code>one_test.go</code>,
|
||||
run <code>gotest one_test.go</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If your change affects performance, add a <code>Benchmark</code> function
|
||||
(see the <a href="/cmd/gotest/">gotest command documentation</a>)
|
||||
and run it using <code>gotest -test.bench=.</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Once your new code is tested and working,
|
||||
it's time to get it <a href="contribute.html">reviewed and submitted</a>.
|
||||
</p>
|
||||
|
||||
<h2 id="pkg_example">An example package with tests</h2>
|
||||
|
||||
<p>
|
||||
This example package, <code>numbers</code>, consists of the function
|
||||
<code>Double</code>, which takes an <code>int</code> and returns that value
|
||||
multiplied by 2. It consists of three files.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
First, the package implementation, <code>numbers.go</code>:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
package newmath
|
||||
package numbers
|
||||
|
||||
import "testing"
|
||||
func Double(i int) int {
|
||||
return i * 2
|
||||
}
|
||||
</pre>
|
||||
|
||||
func TestSqrt(t *testing.T) {
|
||||
const in, out = 4, 2
|
||||
if x := Sqrt(in); x != out {
|
||||
t.Errorf("Sqrt(%v) = %v, want %v", in, x, out)
|
||||
<p>
|
||||
Next, the tests, <code>numbers_test.go</code>:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
package numbers
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
type doubleTest struct {
|
||||
in, out int
|
||||
}
|
||||
|
||||
var doubleTests = []doubleTest{
|
||||
doubleTest{1, 2},
|
||||
doubleTest{2, 4},
|
||||
doubleTest{-5, -10},
|
||||
}
|
||||
|
||||
func TestDouble(t *testing.T) {
|
||||
for _, dt := range doubleTests {
|
||||
v := Double(dt.in)
|
||||
if v != dt.out {
|
||||
t.Errorf("Double(%d) = %d, want %d.", dt.in, v, dt.out)
|
||||
}
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Then run the test with <code>go test</code>:
|
||||
Finally, the <code>Makefile</code>:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
$ <b>go test github.com/user/newmath</b>
|
||||
ok github.com/user/newmath 0.165s
|
||||
include $(GOROOT)/src/Make.inc
|
||||
|
||||
TARG=numbers
|
||||
GOFILES=\
|
||||
numbers.go\
|
||||
|
||||
include $(GOROOT)/src/Make.pkg
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
As always, if you are running the <code>go</code> tool from the package
|
||||
directory, you can omit the package path:
|
||||
Running <code>gomake install</code> will build and install the package to
|
||||
the <code>$GOROOT/pkg/</code> directory (it can then be used by any
|
||||
program on the system).
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Running <code>gomake test</code> (or just running the command
|
||||
<code>gotest</code>) will rebuild the package, including the
|
||||
<code>numbers_test.go</code> file, and then run the <code>TestDouble</code>
|
||||
function. The output "<code>PASS</code>" indicates that all tests passed
|
||||
successfully. Breaking the implementation by changing the multiplier from
|
||||
<code>2</code> to <code>3</code> will allow you to see how failing tests are
|
||||
reported.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
See the <a href="/cmd/gotest/">gotest documentation</a> and the
|
||||
<a href="/pkg/testing/">testing package</a> for more detail.
|
||||
</p>
|
||||
|
||||
<h2 id="arch_os_specific">Architecture- and operating system-specific code</h2>
|
||||
|
||||
<p>First, a disclaimer: very few Go packages should need to know about the
|
||||
hardware and operating system they run on. In the vast majority of cases the
|
||||
language and standard library handle most portability issues. This section is
|
||||
a guide for experienced systems programmers who have a good reason to write
|
||||
platform-specific code, such as assembly-language support for fast
|
||||
trigonometric functions or code that implements a common interface above
|
||||
different operating systems.</p>
|
||||
|
||||
<p>To compile such code, use the <code>$GOOS</code> and <code>$GOARCH</code>
|
||||
<a href="/doc/install.html#environment">environment variables</a> in your
|
||||
source file names and <code>Makefile</code>.</p>
|
||||
|
||||
<p>For example, this <code>Makefile</code> describes a package that builds on
|
||||
different operating systems by parameterizing the file name with
|
||||
<code>$GOOS</code>.</p>
|
||||
|
||||
<pre>
|
||||
include $(GOROOT)/src/Make.inc
|
||||
|
||||
TARG=mypackage
|
||||
GOFILES=\
|
||||
my.go\
|
||||
my_$(GOOS).go\
|
||||
|
||||
include $(GOROOT)/src/Make.pkg
|
||||
</pre>
|
||||
|
||||
<p>The OS-specific code goes in <code>my_linux.go</code>,
|
||||
<code>my_darwin.go</code>, and so on.</p>
|
||||
|
||||
<p>If you follow these conventional parameterizations, tools such as
|
||||
<a href="/cmd/goinstall/">goinstall</a> will work seamlessly with your package:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
$ <b>go test</b>
|
||||
ok github.com/user/newmath 0.165s
|
||||
my_$(GOOS).go
|
||||
my_$(GOARCH).go
|
||||
my_$(GOOS)_$(GOARCH).go
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Run <code><a href="/cmd/go/#hdr-Test_packages">go help test</a></code> and see the
|
||||
<a href="/pkg/testing/">testing package documentation</a> for more detail.
|
||||
</p>
|
||||
|
||||
|
||||
<h2 id="remote">Remote packages</h2>
|
||||
|
||||
<p>
|
||||
An import path can describe how to obtain the package source code using a
|
||||
revision control system such as Git or Mercurial. The <code>go</code> tool uses
|
||||
this property to automatically fetch packages from remote repositories.
|
||||
For instance, the examples described in this document are also kept in a
|
||||
Mercurial repository hosted at Google Code,
|
||||
<code><a href="//code.google.com/p/go.example">code.google.com/p/go.example</a></code>.
|
||||
If you include the repository URL in the package's import path,
|
||||
<code>go get</code> will fetch, build, and install it automatically:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
$ <b>go get code.google.com/p/go.example/hello</b>
|
||||
$ <b>$GOPATH/bin/hello</b>
|
||||
Hello, world. Sqrt(2) = 1.414213562373095
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
If the specified package is not present in a workspace, <code>go get</code>
|
||||
will place it inside the first workspace specified by <code>GOPATH</code>.
|
||||
(If the package does already exist, <code>go get</code> skips the remote
|
||||
fetch and behaves the same as <code>go install</code>.)
|
||||
</p>
|
||||
|
||||
<p>
|
||||
After issuing the above <code>go get</code> command, the workspace directory
|
||||
tree should now look like this:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
bin/
|
||||
hello # command executable
|
||||
pkg/
|
||||
linux_amd64/
|
||||
code.google.com/p/go.example/
|
||||
newmath.a # package object
|
||||
github.com/user/
|
||||
newmath.a # package object
|
||||
src/
|
||||
code.google.com/p/go.example/
|
||||
hello/
|
||||
hello.go # command source
|
||||
newmath/
|
||||
sqrt.go # package source
|
||||
sqrt_test.go # test source
|
||||
github.com/user/
|
||||
hello/
|
||||
hello.go # command source
|
||||
newmath/
|
||||
sqrt.go # package source
|
||||
sqrt_test.go # test source
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The <code>hello</code> command hosted at Google Code depends on the
|
||||
<code>newmath</code> package within the same repository. The imports in
|
||||
<code>hello.go</code> file use the same import path convention, so the <code>go
|
||||
get</code> command is able to locate and install the dependent package, too.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
import "code.google.com/p/go.example/newmath"
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
This convention is the easiest way to make your Go packages available for
|
||||
others to use.
|
||||
The <a href="//code.google.com/p/go-wiki/wiki/Projects">Go Wiki</a>
|
||||
and <a href="//godoc.org/">godoc.org</a>
|
||||
provide lists of external Go projects.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
For more information on using remote repositories with the <code>go</code> tool, see
|
||||
<code><a href="/cmd/go/#hdr-Remote_import_paths">go help importpath</a></code>.
|
||||
</p>
|
||||
|
||||
|
||||
<h2 id="next">What's next</h2>
|
||||
|
||||
<p>
|
||||
Subscribe to the
|
||||
<a href="//groups.google.com/group/golang-announce">golang-announce</a>
|
||||
mailing list to be notified when a new stable version of Go is released.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
See <a href="/doc/effective_go.html">Effective Go</a> for tips on writing
|
||||
clear, idiomatic Go code.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Take <a href="//tour.golang.org/">A Tour of Go</a> to learn the language
|
||||
proper.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Visit the <a href="/doc/#articles">documentation page</a> for a set of in-depth
|
||||
articles about the Go language and its libraries and tools.
|
||||
</p>
|
||||
|
||||
|
||||
<h2 id="help">Getting help</h2>
|
||||
|
||||
<p>
|
||||
For real-time help, ask the helpful gophers in <code>#go-nuts</code> on the
|
||||
<a href="http://freenode.net/">Freenode</a> IRC server.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The official mailing list for discussion of the Go language is
|
||||
<a href="//groups.google.com/group/golang-nuts">Go Nuts</a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Report bugs using the
|
||||
<a href="//code.google.com/p/go/issues/list">Go issue tracker</a>.
|
||||
</p>
|
||||
<p>The same holds for <code>.s</code> (assembly) files.</p>
|
||||
|
||||
25
doc/codelab/wiki/Makefile
Normal file
@@ -0,0 +1,25 @@
|
||||
# Copyright 2010 The Go Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style
|
||||
# license that can be found in the LICENSE file.
|
||||
|
||||
include ../../../src/Make.inc
|
||||
|
||||
all: index.html
|
||||
|
||||
include ../../../src/Make.common
|
||||
|
||||
CLEANFILES+=index.html srcextract.bin htmlify.bin get.bin
|
||||
|
||||
index.html: srcextract.bin htmlify.bin
|
||||
PATH=.:$$PATH awk '/^!/{system(substr($$0,2)); next} {print}' < wiki.html | tr -d '\r' > index.html
|
||||
|
||||
test: get.bin
|
||||
bash ./test.sh
|
||||
rm -f get.6 get.bin
|
||||
|
||||
%.bin: %.$O
|
||||
$(LD) -o $@ $<
|
||||
|
||||
%.$O: %.go
|
||||
$(GC) $*.go
|
||||
|
||||
6
doc/codelab/wiki/edit.html
Normal file
@@ -0,0 +1,6 @@
|
||||
<h1>Editing {Title}</h1>
|
||||
|
||||
<form action="/save/{Title}" method="POST">
|
||||
<div><textarea name="body" rows="20" cols="80">{Body|html}</textarea></div>
|
||||
<div><input type="submit" value="Save"></div>
|
||||
</form>
|
||||
100
doc/codelab/wiki/final-noclosure.go
Normal file
@@ -0,0 +1,100 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"http"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"regexp"
|
||||
"template"
|
||||
)
|
||||
|
||||
type Page struct {
|
||||
Title string
|
||||
Body []byte
|
||||
}
|
||||
|
||||
func (p *Page) save() os.Error {
|
||||
filename := p.Title + ".txt"
|
||||
return ioutil.WriteFile(filename, p.Body, 0600)
|
||||
}
|
||||
|
||||
func loadPage(title string) (*Page, os.Error) {
|
||||
filename := title + ".txt"
|
||||
body, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Page{Title: title, Body: body}, nil
|
||||
}
|
||||
|
||||
func viewHandler(w http.ResponseWriter, r *http.Request) {
|
||||
title, err := getTitle(w, r)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
p, err := loadPage(title)
|
||||
if err != nil {
|
||||
http.Redirect(w, r, "/edit/"+title, http.StatusFound)
|
||||
return
|
||||
}
|
||||
renderTemplate(w, "view", p)
|
||||
}
|
||||
|
||||
func editHandler(w http.ResponseWriter, r *http.Request) {
|
||||
title, err := getTitle(w, r)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
p, err := loadPage(title)
|
||||
if err != nil {
|
||||
p = &Page{Title: title}
|
||||
}
|
||||
renderTemplate(w, "edit", p)
|
||||
}
|
||||
|
||||
func saveHandler(w http.ResponseWriter, r *http.Request) {
|
||||
title, err := getTitle(w, r)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
body := r.FormValue("body")
|
||||
p := &Page{Title: title, Body: []byte(body)}
|
||||
err = p.save()
|
||||
if err != nil {
|
||||
http.Error(w, err.String(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
http.Redirect(w, r, "/view/"+title, http.StatusFound)
|
||||
}
|
||||
|
||||
func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) {
|
||||
t, err := template.ParseFile(tmpl+".html", nil)
|
||||
if err != nil {
|
||||
http.Error(w, err.String(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
err = t.Execute(w, p)
|
||||
if err != nil {
|
||||
http.Error(w, err.String(), http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
const lenPath = len("/view/")
|
||||
|
||||
var titleValidator = regexp.MustCompile("^[a-zA-Z0-9]+$")
|
||||
|
||||
func getTitle(w http.ResponseWriter, r *http.Request) (title string, err os.Error) {
|
||||
title = r.URL.Path[lenPath:]
|
||||
if !titleValidator.MatchString(title) {
|
||||
http.NotFound(w, r)
|
||||
err = os.NewError("Invalid Page Title")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func main() {
|
||||
http.HandleFunc("/view/", viewHandler)
|
||||
http.HandleFunc("/edit/", editHandler)
|
||||
http.HandleFunc("/save/", saveHandler)
|
||||
http.ListenAndServe(":8080", nil)
|
||||
}
|
||||
52
doc/codelab/wiki/final-noerror.go
Normal file
@@ -0,0 +1,52 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"http"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"template"
|
||||
)
|
||||
|
||||
type Page struct {
|
||||
Title string
|
||||
Body []byte
|
||||
}
|
||||
|
||||
func (p *Page) save() os.Error {
|
||||
filename := p.Title + ".txt"
|
||||
return ioutil.WriteFile(filename, p.Body, 0600)
|
||||
}
|
||||
|
||||
func loadPage(title string) (*Page, os.Error) {
|
||||
filename := title + ".txt"
|
||||
body, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Page{Title: title, Body: body}, nil
|
||||
}
|
||||
|
||||
const lenPath = len("/view/")
|
||||
|
||||
func editHandler(w http.ResponseWriter, r *http.Request) {
|
||||
title := r.URL.Path[lenPath:]
|
||||
p, err := loadPage(title)
|
||||
if err != nil {
|
||||
p = &Page{Title: title}
|
||||
}
|
||||
t, _ := template.ParseFile("edit.html", nil)
|
||||
t.Execute(w, p)
|
||||
}
|
||||
|
||||
func viewHandler(w http.ResponseWriter, r *http.Request) {
|
||||
title := r.URL.Path[lenPath:]
|
||||
p, _ := loadPage(title)
|
||||
t, _ := template.ParseFile("view.html", nil)
|
||||
t.Execute(w, p)
|
||||
}
|
||||
|
||||
func main() {
|
||||
http.HandleFunc("/view/", viewHandler)
|
||||
http.HandleFunc("/edit/", editHandler)
|
||||
http.ListenAndServe(":8080", nil)
|
||||
}
|
||||
90
doc/codelab/wiki/final-parsetemplate.go
Normal file
@@ -0,0 +1,90 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"http"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"regexp"
|
||||
"template"
|
||||
)
|
||||
|
||||
type Page struct {
|
||||
Title string
|
||||
Body []byte
|
||||
}
|
||||
|
||||
func (p *Page) save() os.Error {
|
||||
filename := p.Title + ".txt"
|
||||
return ioutil.WriteFile(filename, p.Body, 0600)
|
||||
}
|
||||
|
||||
func loadPage(title string) (*Page, os.Error) {
|
||||
filename := title + ".txt"
|
||||
body, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Page{Title: title, Body: body}, nil
|
||||
}
|
||||
|
||||
func viewHandler(w http.ResponseWriter, r *http.Request, title string) {
|
||||
p, err := loadPage(title)
|
||||
if err != nil {
|
||||
http.Redirect(w, r, "/edit/"+title, http.StatusFound)
|
||||
return
|
||||
}
|
||||
renderTemplate(w, "view", p)
|
||||
}
|
||||
|
||||
func editHandler(w http.ResponseWriter, r *http.Request, title string) {
|
||||
p, err := loadPage(title)
|
||||
if err != nil {
|
||||
p = &Page{Title: title}
|
||||
}
|
||||
renderTemplate(w, "edit", p)
|
||||
}
|
||||
|
||||
func saveHandler(w http.ResponseWriter, r *http.Request, title string) {
|
||||
body := r.FormValue("body")
|
||||
p := &Page{Title: title, Body: []byte(body)}
|
||||
err := p.save()
|
||||
if err != nil {
|
||||
http.Error(w, err.String(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
http.Redirect(w, r, "/view/"+title, http.StatusFound)
|
||||
}
|
||||
|
||||
func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) {
|
||||
t, err := template.ParseFile(tmpl+".html", nil)
|
||||
if err != nil {
|
||||
http.Error(w, err.String(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
err = t.Execute(w, p)
|
||||
if err != nil {
|
||||
http.Error(w, err.String(), http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
const lenPath = len("/view/")
|
||||
|
||||
var titleValidator = regexp.MustCompile("^[a-zA-Z0-9]+$")
|
||||
|
||||
func makeHandler(fn func(http.ResponseWriter, *http.Request, string)) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
title := r.URL.Path[lenPath:]
|
||||
if !titleValidator.MatchString(title) {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
fn(w, r, title)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
http.HandleFunc("/view/", makeHandler(viewHandler))
|
||||
http.HandleFunc("/edit/", makeHandler(editHandler))
|
||||
http.HandleFunc("/save/", makeHandler(saveHandler))
|
||||
http.ListenAndServe(":8080", nil)
|
||||
}
|
||||
64
doc/codelab/wiki/final-template.go
Normal file
@@ -0,0 +1,64 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"http"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"template"
|
||||
)
|
||||
|
||||
type Page struct {
|
||||
Title string
|
||||
Body []byte
|
||||
}
|
||||
|
||||
func (p *Page) save() os.Error {
|
||||
filename := p.Title + ".txt"
|
||||
return ioutil.WriteFile(filename, p.Body, 0600)
|
||||
}
|
||||
|
||||
func loadPage(title string) (*Page, os.Error) {
|
||||
filename := title + ".txt"
|
||||
body, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Page{Title: title, Body: body}, nil
|
||||
}
|
||||
|
||||
const lenPath = len("/view/")
|
||||
|
||||
func editHandler(w http.ResponseWriter, r *http.Request) {
|
||||
title := r.URL.Path[lenPath:]
|
||||
p, err := loadPage(title)
|
||||
if err != nil {
|
||||
p = &Page{Title: title}
|
||||
}
|
||||
renderTemplate(w, "edit", p)
|
||||
}
|
||||
|
||||
func viewHandler(w http.ResponseWriter, r *http.Request) {
|
||||
title := r.URL.Path[lenPath:]
|
||||
p, _ := loadPage(title)
|
||||
renderTemplate(w, "view", p)
|
||||
}
|
||||
|
||||
func saveHandler(w http.ResponseWriter, r *http.Request) {
|
||||
title := r.URL.Path[lenPath:]
|
||||
body := r.FormValue("body")
|
||||
p := &Page{Title: title, Body: []byte(body)}
|
||||
p.save()
|
||||
http.Redirect(w, r, "/view/"+title, http.StatusFound)
|
||||
}
|
||||
|
||||
func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) {
|
||||
t, _ := template.ParseFile(tmpl+".html", nil)
|
||||
t.Execute(w, p)
|
||||
}
|
||||
|
||||
func main() {
|
||||
http.HandleFunc("/view/", viewHandler)
|
||||
http.HandleFunc("/edit/", editHandler)
|
||||
http.HandleFunc("/save/", saveHandler)
|
||||
http.ListenAndServe(":8080", nil)
|
||||
}
|
||||
93
doc/codelab/wiki/final.go
Normal file
@@ -0,0 +1,93 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"http"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"regexp"
|
||||
"template"
|
||||
)
|
||||
|
||||
type Page struct {
|
||||
Title string
|
||||
Body []byte
|
||||
}
|
||||
|
||||
func (p *Page) save() os.Error {
|
||||
filename := p.Title + ".txt"
|
||||
return ioutil.WriteFile(filename, p.Body, 0600)
|
||||
}
|
||||
|
||||
func loadPage(title string) (*Page, os.Error) {
|
||||
filename := title + ".txt"
|
||||
body, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Page{Title: title, Body: body}, nil
|
||||
}
|
||||
|
||||
func viewHandler(w http.ResponseWriter, r *http.Request, title string) {
|
||||
p, err := loadPage(title)
|
||||
if err != nil {
|
||||
http.Redirect(w, r, "/edit/"+title, http.StatusFound)
|
||||
return
|
||||
}
|
||||
renderTemplate(w, "view", p)
|
||||
}
|
||||
|
||||
func editHandler(w http.ResponseWriter, r *http.Request, title string) {
|
||||
p, err := loadPage(title)
|
||||
if err != nil {
|
||||
p = &Page{Title: title}
|
||||
}
|
||||
renderTemplate(w, "edit", p)
|
||||
}
|
||||
|
||||
func saveHandler(w http.ResponseWriter, r *http.Request, title string) {
|
||||
body := r.FormValue("body")
|
||||
p := &Page{Title: title, Body: []byte(body)}
|
||||
err := p.save()
|
||||
if err != nil {
|
||||
http.Error(w, err.String(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
http.Redirect(w, r, "/view/"+title, http.StatusFound)
|
||||
}
|
||||
|
||||
var templates = make(map[string]*template.Template)
|
||||
|
||||
func init() {
|
||||
for _, tmpl := range []string{"edit", "view"} {
|
||||
templates[tmpl] = template.MustParseFile(tmpl+".html", nil)
|
||||
}
|
||||
}
|
||||
|
||||
func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) {
|
||||
err := templates[tmpl].Execute(w, p)
|
||||
if err != nil {
|
||||
http.Error(w, err.String(), http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
const lenPath = len("/view/")
|
||||
|
||||
var titleValidator = regexp.MustCompile("^[a-zA-Z0-9]+$")
|
||||
|
||||
func makeHandler(fn func(http.ResponseWriter, *http.Request, string)) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
title := r.URL.Path[lenPath:]
|
||||
if !titleValidator.MatchString(title) {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
fn(w, r, title)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
http.HandleFunc("/view/", makeHandler(viewHandler))
|
||||
http.HandleFunc("/edit/", makeHandler(editHandler))
|
||||
http.HandleFunc("/save/", makeHandler(saveHandler))
|
||||
http.ListenAndServe(":8080", nil)
|
||||
}
|
||||
50
doc/codelab/wiki/get.go
Normal file
@@ -0,0 +1,50 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"http"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
post = flag.String("post", "", "urlencoded form data to POST")
|
||||
addr = flag.Bool("addr", false, "find open address and print to stdout")
|
||||
)
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
if *addr {
|
||||
l, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer l.Close()
|
||||
fmt.Print(l.Addr())
|
||||
return
|
||||
}
|
||||
url := flag.Arg(0)
|
||||
if url == "" {
|
||||
log.Fatal("no url supplied")
|
||||
}
|
||||
var r *http.Response
|
||||
var err os.Error
|
||||
if *post != "" {
|
||||
b := strings.NewReader(*post)
|
||||
r, err = http.Post(url, "application/x-www-form-urlencoded", b)
|
||||
} else {
|
||||
r, _, err = http.Get(url)
|
||||
}
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer r.Body.Close()
|
||||
_, err = io.Copy(os.Stdout, r.Body)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
12
doc/codelab/wiki/htmlify.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"template"
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
b, _ := ioutil.ReadAll(os.Stdin)
|
||||
template.HTMLFormatter(os.Stdout, "", b)
|
||||
}
|
||||
@@ -2,7 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"http"
|
||||
)
|
||||
|
||||
func handler(w http.ResponseWriter, r *http.Request) {
|
||||
1003
doc/codelab/wiki/index.html
Normal file
@@ -1,13 +1,10 @@
|
||||
// Copyright 2010 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"http"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
)
|
||||
|
||||
type Page struct {
|
||||
@@ -15,12 +12,12 @@ type Page struct {
|
||||
Body []byte
|
||||
}
|
||||
|
||||
func (p *Page) save() error {
|
||||
func (p *Page) save() os.Error {
|
||||
filename := p.Title + ".txt"
|
||||
return ioutil.WriteFile(filename, p.Body, 0600)
|
||||
}
|
||||
|
||||
func loadPage(title string) (*Page, error) {
|
||||
func loadPage(title string) (*Page, os.Error) {
|
||||
filename := title + ".txt"
|
||||
body, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
@@ -29,14 +26,16 @@ func loadPage(title string) (*Page, error) {
|
||||
return &Page{Title: title, Body: body}, nil
|
||||
}
|
||||
|
||||
const lenPath = len("/view/")
|
||||
|
||||
func viewHandler(w http.ResponseWriter, r *http.Request) {
|
||||
title := r.URL.Path[len("/view/"):]
|
||||
title := r.URL.Path[lenPath:]
|
||||
p, _ := loadPage(title)
|
||||
fmt.Fprintf(w, "<h1>%s</h1><div>%s</div>", p.Title, p.Body)
|
||||
}
|
||||
|
||||
func editHandler(w http.ResponseWriter, r *http.Request) {
|
||||
title := r.URL.Path[len("/edit/"):]
|
||||
title := r.URL.Path[lenPath:]
|
||||
p, err := loadPage(title)
|
||||
if err != nil {
|
||||
p = &Page{Title: title}
|
||||
30
doc/codelab/wiki/part1-noerror.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
)
|
||||
|
||||
type Page struct {
|
||||
Title string
|
||||
Body []byte
|
||||
}
|
||||
|
||||
func (p *Page) save() os.Error {
|
||||
filename := p.Title + ".txt"
|
||||
return ioutil.WriteFile(filename, p.Body, 0600)
|
||||
}
|
||||
|
||||
func loadPage(title string) *Page {
|
||||
filename := title + ".txt"
|
||||
body, _ := ioutil.ReadFile(filename)
|
||||
return &Page{Title: title, Body: body}
|
||||
}
|
||||
|
||||
func main() {
|
||||
p1 := &Page{Title: "TestPage", Body: []byte("This is a sample page.")}
|
||||
p1.save()
|
||||
p2 := loadPage("TestPage")
|
||||
fmt.Println(string(p2.Body))
|
||||
}
|
||||
33
doc/codelab/wiki/part1.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
)
|
||||
|
||||
type Page struct {
|
||||
Title string
|
||||
Body []byte
|
||||
}
|
||||
|
||||
func (p *Page) save() os.Error {
|
||||
filename := p.Title + ".txt"
|
||||
return ioutil.WriteFile(filename, p.Body, 0600)
|
||||
}
|
||||
|
||||
func loadPage(title string) (*Page, os.Error) {
|
||||
filename := title + ".txt"
|
||||
body, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Page{Title: title, Body: body}, nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
p1 := &Page{Title: "TestPage", Body: []byte("This is a sample Page.")}
|
||||
p1.save()
|
||||
p2, _ := loadPage("TestPage")
|
||||
fmt.Println(string(p2.Body))
|
||||
}
|
||||
40
doc/codelab/wiki/part2.go
Normal file
@@ -0,0 +1,40 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"http"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
)
|
||||
|
||||
type Page struct {
|
||||
Title string
|
||||
Body []byte
|
||||
}
|
||||
|
||||
func (p *Page) save() os.Error {
|
||||
filename := p.Title + ".txt"
|
||||
return ioutil.WriteFile(filename, p.Body, 0600)
|
||||
}
|
||||
|
||||
func loadPage(title string) (*Page, os.Error) {
|
||||
filename := title + ".txt"
|
||||
body, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Page{Title: title, Body: body}, nil
|
||||
}
|
||||
|
||||
const lenPath = len("/view/")
|
||||
|
||||
func viewHandler(w http.ResponseWriter, r *http.Request) {
|
||||
title := r.URL.Path[lenPath:]
|
||||
p, _ := loadPage(title)
|
||||
fmt.Fprintf(w, "<h1>%s</h1><div>%s</div>", p.Title, p.Body)
|
||||
}
|
||||
|
||||
func main() {
|
||||
http.HandleFunc("/view/", viewHandler)
|
||||
http.ListenAndServe(":8080", nil)
|
||||
}
|
||||
72
doc/codelab/wiki/srcextract.go
Normal file
@@ -0,0 +1,72 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"flag"
|
||||
"go/parser"
|
||||
"go/printer"
|
||||
"go/ast"
|
||||
"go/token"
|
||||
"log"
|
||||
"os"
|
||||
"template"
|
||||
)
|
||||
|
||||
var (
|
||||
srcFn = flag.String("src", "", "source filename")
|
||||
getName = flag.String("name", "", "func/type name to output")
|
||||
html = flag.Bool("html", true, "output HTML")
|
||||
showPkg = flag.Bool("pkg", false, "show package in output")
|
||||
)
|
||||
|
||||
func main() {
|
||||
// handle input
|
||||
flag.Parse()
|
||||
if *srcFn == "" || *getName == "" {
|
||||
flag.Usage()
|
||||
os.Exit(2)
|
||||
}
|
||||
// load file
|
||||
fs := token.NewFileSet()
|
||||
file, err := parser.ParseFile(fs, *srcFn, nil, 0)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
// create filter
|
||||
filter := func(name string) bool {
|
||||
return name == *getName
|
||||
}
|
||||
// filter
|
||||
if !ast.FilterFile(file, filter) {
|
||||
os.Exit(1)
|
||||
}
|
||||
// print the AST
|
||||
var b bytes.Buffer
|
||||
printer.Fprint(&b, fs, file)
|
||||
// drop package declaration
|
||||
if !*showPkg {
|
||||
for {
|
||||
c, err := b.ReadByte()
|
||||
if c == '\n' || err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
// drop leading newlines
|
||||
for {
|
||||
b, err := b.ReadByte()
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
if b != '\n' {
|
||||
os.Stdout.Write([]byte{b})
|
||||
break
|
||||
}
|
||||
}
|
||||
// output
|
||||
if *html {
|
||||
template.HTMLEscape(os.Stdout, b.Bytes())
|
||||
} else {
|
||||
b.WriteTo(os.Stdout)
|
||||
}
|
||||
}
|
||||
27
doc/codelab/wiki/test.sh
Executable file
@@ -0,0 +1,27 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
wiki_pid=
|
||||
cleanup() {
|
||||
kill $wiki_pid
|
||||
rm -f test_*.out Test.txt final-test.bin final-test.go
|
||||
}
|
||||
trap cleanup 0 INT
|
||||
|
||||
gomake get.bin
|
||||
addr=$(./get.bin -addr)
|
||||
sed s/:8080/$addr/ < final.go > final-test.go
|
||||
gomake final-test.bin
|
||||
(./final-test.bin) &
|
||||
wiki_pid=$!
|
||||
|
||||
sleep 1
|
||||
|
||||
./get.bin http://$addr/edit/Test > test_edit.out
|
||||
diff -u test_edit.out test_edit.good
|
||||
./get.bin -post=body=some%20content http://$addr/save/Test
|
||||
diff -u Test.txt test_Test.txt.good
|
||||
./get.bin http://$addr/view/Test > test_view.out
|
||||
diff -u test_view.out test_view.good
|
||||
|
||||
echo PASS
|
||||
5
doc/codelab/wiki/view.html
Normal file
@@ -0,0 +1,5 @@
|
||||
<h1>{Title}</h1>
|
||||
|
||||
<p>[<a href="/edit/{Title}">edit</a>]</p>
|
||||
|
||||
<div>{Body}</div>
|
||||
781
doc/codelab/wiki/wiki.html
Normal file
@@ -0,0 +1,781 @@
|
||||
<!-- Codelab: Writing Web Applications -->
|
||||
<h2>Introduction</h2>
|
||||
|
||||
<p>
|
||||
Covered in this codelab:
|
||||
</p>
|
||||
<ul>
|
||||
<li>Creating a data structure with load and save methods</li>
|
||||
<li>Using the <code>http</code> package to build web applications
|
||||
<li>Using the <code>template</code> package to process HTML templates</li>
|
||||
<li>Using the <code>regexp</code> package to validate user input</li>
|
||||
<li>Using closures</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
Assumed knowledge:
|
||||
</p>
|
||||
<ul>
|
||||
<li>Programming experience</li>
|
||||
<li>Understanding of basic web technologies (HTTP, HTML)</li>
|
||||
<li>Some UNIX command-line knowledge</li>
|
||||
</ul>
|
||||
|
||||
<h2>Getting Started</h2>
|
||||
|
||||
<p>
|
||||
At present, you need to have a Linux, OS X, or FreeBSD machine to run Go. If
|
||||
you don't have access to one, you could set up a Linux Virtual Machine (using
|
||||
<a href="http://www.virtualbox.org/">VirtualBox</a> or similar) or a
|
||||
<a href="http://www.google.com/search?q=virtual+private+server">Virtual
|
||||
Private Server</a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Install Go (see the <a href="http://golang.org/doc/install.html">Installation Instructions</a>).
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Make a new directory for this codelab and cd to it:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
$ mkdir ~/gowiki
|
||||
$ cd ~/gowiki
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Create a file named <code>wiki.go</code>, open it in your favorite editor, and
|
||||
add the following lines:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
)
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
We import the <code>fmt</code>, <code>ioutil</code> and <code>os</code>
|
||||
packages from the Go standard library. Later, as we implement additional
|
||||
functionality, we will add more packages to this <code>import</code>
|
||||
declaration.
|
||||
</p>
|
||||
|
||||
<h2>Data Structures</h2>
|
||||
|
||||
<p>
|
||||
Let's start by defining the data structures. A wiki consists of a series of
|
||||
interconnected pages, each of which has a title and a body (the page content).
|
||||
Here, we define <code>Page</code> as a struct with two fields representing
|
||||
the title and body.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
!srcextract.bin -src=part1.go -name=Page
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The type <code>[]byte</code> means "a <code>byte</code> slice".
|
||||
(See <a href="http://golang.org/doc/effective_go.html#slices">Effective Go</a>
|
||||
for more on slices.)
|
||||
The <code>Body</code> element is a <code>[]byte</code> rather than
|
||||
<code>string</code> because that is the type expected by the <code>io</code>
|
||||
libraries we will use, as you'll see below.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The <code>Page</code> struct describes how page data will be stored in memory.
|
||||
But what about persistent storage? We can address that by creating a
|
||||
<code>save</code> method on <code>Page</code>:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
!srcextract.bin -src=part1.go -name=save
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
This method's signature reads: "This is a method named <code>save</code> that
|
||||
takes as its receiver <code>p</code>, a pointer to <code>Page</code> . It takes
|
||||
no parameters, and returns a value of type <code>os.Error</code>."
|
||||
</p>
|
||||
|
||||
<p>
|
||||
This method will save the <code>Page</code>'s <code>Body</code> to a text
|
||||
file. For simplicity, we will use the <code>Title</code> as the file name.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The <code>save</code> method returns an <code>os.Error</code> value because
|
||||
that is the return type of <code>WriteFile</code> (a standard library function
|
||||
that writes a byte slice to a file). The <code>save</code> method returns the
|
||||
error value, to let the application handle it should anything go wrong while
|
||||
writing the file. If all goes well, <code>Page.save()</code> will return
|
||||
<code>nil</code> (the zero-value for pointers, interfaces, and some other
|
||||
types).
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The octal integer constant <code>0600</code>, passed as the third parameter to
|
||||
<code>WriteFile</code>, indicates that the file should be created with
|
||||
read-write permissions for the current user only. (See the Unix man page
|
||||
<code>open(2)</code> for details.)
|
||||
</p>
|
||||
|
||||
<p>
|
||||
We will want to load pages, too:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
!srcextract.bin -src=part1-noerror.go -name=loadPage
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The function <code>loadPage</code> constructs the file name from
|
||||
<code>Title</code>, reads the file's contents into a new
|
||||
<code>Page</code>, and returns a pointer to that new <code>page</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Functions can return multiple values. The standard library function
|
||||
<code>io.ReadFile</code> returns <code>[]byte</code> and <code>os.Error</code>.
|
||||
In <code>loadPage</code>, error isn't being handled yet; the "blank identifier"
|
||||
represented by the underscore (<code>_</code>) symbol is used to throw away the
|
||||
error return value (in essence, assigning the value to nothing).
|
||||
</p>
|
||||
|
||||
<p>
|
||||
But what happens if <code>ReadFile</code> encounters an error? For example,
|
||||
the file might not exist. We should not ignore such errors. Let's modify the
|
||||
function to return <code>*Page</code> and <code>os.Error</code>.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
!srcextract.bin -src=part1.go -name=loadPage
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Callers of this function can now check the second parameter; if it is
|
||||
<code>nil</code> then it has successfully loaded a Page. If not, it will be an
|
||||
<code>os.Error</code> that can be handled by the caller (see the <a
|
||||
href="http://golang.org/pkg/os/#Error">os package documentation</a> for
|
||||
details).
|
||||
</p>
|
||||
|
||||
<p>
|
||||
At this point we have a simple data structure and the ability to save to and
|
||||
load from a file. Let's write a <code>main</code> function to test what we've
|
||||
written:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
!srcextract.bin -src=part1.go -name=main
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
After compiling and executing this code, a file named <code>TestPage.txt</code>
|
||||
would be created, containing the contents of <code>p1</code>. The file would
|
||||
then be read into the struct <code>p2</code>, and its <code>Body</code> element
|
||||
printed to the screen.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
You can compile and run the program like this:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
$ 8g wiki.go
|
||||
$ 8l wiki.8
|
||||
$ ./8.out
|
||||
This is a sample page.
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
(The <code>8g</code> and <code>8l</code> commands are applicable to
|
||||
<code>GOARCH=386</code>. If you're on an <code>amd64</code> system,
|
||||
substitute 6's for the 8's.)
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<a href="part1.go">Click here to view the code we've written so far.</a>
|
||||
</p>
|
||||
|
||||
<h2>Introducing the <code>http</code> package (an interlude)</h2>
|
||||
|
||||
<p>
|
||||
Here's a full working example of a simple web server:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
!htmlify.bin < http-sample.go
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The <code>main</code> function begins with a call to
|
||||
<code>http.HandleFunc</code>, which tells the <code>http</code> package to
|
||||
handle all requests to the web root (<code>"/"</code>) with
|
||||
<code>handler</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
It then calls <code>http.ListenAndServe</code>, specifying that it should
|
||||
listen on port 8080 on any interface (<code>":8080"</code>). (Don't
|
||||
worry about its second parameter, <code>nil</code>, for now.)
|
||||
This function will block until the program is terminated.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The function <code>handler</code> is of the type <code>http.HandlerFunc</code>.
|
||||
It takes an <code>http.ResponseWriter</code> and an <code>http.Request</code> as
|
||||
its arguments.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
An <code>http.ResponseWriter</code> value assembles the HTTP server's response; by writing
|
||||
to it, we send data to the HTTP client.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
An <code>http.Request</code> is a data structure that represents the client
|
||||
HTTP request. The string <code>r.URL.Path</code> is the path component
|
||||
of the request URL. The trailing <code>[1:]</code> means
|
||||
"create a sub-slice of <code>Path</code> from the 1st character to the end."
|
||||
This drops the leading "/" from the path name.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If you run this program and access the URL:
|
||||
</p>
|
||||
<pre>http://localhost:8080/monkeys</pre>
|
||||
<p>
|
||||
the program would present a page containing:
|
||||
</p>
|
||||
<pre>Hi there, I love monkeys!</pre>
|
||||
|
||||
<h2>Using <code>http</code> to serve wiki pages</h2>
|
||||
|
||||
<p>
|
||||
To use the <code>http</code> package, it must be imported:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
import (
|
||||
"fmt"
|
||||
<b>"http"</b>
|
||||
"io/ioutil"
|
||||
"os"
|
||||
)
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Let's create a handler to view a wiki page:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
!srcextract.bin -src=part2.go -name=lenPath
|
||||
|
||||
!srcextract.bin -src=part2.go -name=viewHandler
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
First, this function extracts the page title from <code>r.URL.Path</code>,
|
||||
the path component of the request URL. The global constant
|
||||
<code>lenPath</code> is the length of the leading <code>"/view/"</code>
|
||||
component of the request path.
|
||||
The <code>Path</code> is re-sliced with <code>[lenPath:]</code> to drop the
|
||||
first 6 characters of the string. This is because the path will invariably
|
||||
begin with <code>"/view/"</code>, which is not part of the page title.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The function then loads the page data, formats the page with a string of simple
|
||||
HTML, and writes it to <code>w</code>, the <code>http.ResponseWriter</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Again, note the use of <code>_</code> to ignore the <code>os.Error</code>
|
||||
return value from <code>loadPage</code>. This is done here for simplicity
|
||||
and generally considered bad practice. We will attend to this later.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
To use this handler, we create a <code>main</code> function that
|
||||
initializes <code>http</code> using the <code>viewHandler</code> to handle
|
||||
any requests under the path <code>/view/</code>.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
!srcextract.bin -src=part2.go -name=main
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
<a href="part2.go">Click here to view the code we've written so far.</a>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Let's create some page data (as <code>test.txt</code>), compile our code, and
|
||||
try serving a wiki page:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
$ echo "Hello world" > test.txt
|
||||
$ 8g wiki.go
|
||||
$ 8l wiki.8
|
||||
$ ./8.out
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
With this web server running, a visit to <code><a
|
||||
href="http://localhost:8080/view/test">http://localhost:8080/view/test</a></code>
|
||||
should show a page titled "test" containing the words "Hello world".
|
||||
</p>
|
||||
|
||||
<h2>Editing Pages</h2>
|
||||
|
||||
<p>
|
||||
A wiki is not a wiki without the ability to edit pages. Let's create two new
|
||||
handlers: one named <code>editHandler</code> to display an 'edit page' form,
|
||||
and the other named <code>saveHandler</code> to save the data entered via the
|
||||
form.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
First, we add them to <code>main()</code>:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
!srcextract.bin -src=final-noclosure.go -name=main
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The function <code>editHandler</code> loads the page
|
||||
(or, if it doesn't exist, create an empty <code>Page</code> struct),
|
||||
and displays an HTML form.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
!srcextract.bin -src=notemplate.go -name=editHandler
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
This function will work fine, but all that hard-coded HTML is ugly.
|
||||
Of course, there is a better way.
|
||||
</p>
|
||||
|
||||
<h2>The <code>template</code> package</h2>
|
||||
|
||||
<p>
|
||||
The <code>template</code> package is part of the Go standard library. We can
|
||||
use <code>template</code> to keep the HTML in a separate file, allowing
|
||||
us to change the layout of our edit page without modifying the underlying Go
|
||||
code.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
First, we must add <code>template</code> to the list of imports:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
import (
|
||||
"http"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
<b>"template"</b>
|
||||
)
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Let's create a template file containing the HTML form.
|
||||
Open a new file named <code>edit.html</code>, and add the following lines:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
!htmlify.bin < edit.html
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Modify <code>editHandler</code> to use the template, instead of the hard-coded
|
||||
HTML:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
!srcextract.bin -src=final-noerror.go -name=editHandler
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The function <code>template.ParseFile</code> will read the contents of
|
||||
<code>edit.html</code> and return a <code>*template.Template</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The method <code>t.Execute</code> replaces all occurrences of
|
||||
<code>{Title}</code> and <code>{Body}</code> with the values of
|
||||
<code>p.Title</code> and <code>p.Body</code>, and writes the resultant
|
||||
HTML to the <code>http.ResponseWriter</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Note that we've used <code>{Body|html}</code> in the above template.
|
||||
The <code>|html</code> part asks the template engine to pass the value
|
||||
<code>Body</code> through the <code>html</code> formatter before outputting it,
|
||||
which escapes HTML characters (such as replacing <code>></code> with
|
||||
<code>&gt;</code>).
|
||||
This will prevent user data from corrupting the form HTML.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Now that we've removed the <code>fmt.Sprintf</code> statement, we can remove
|
||||
<code>"fmt"</code> from the <code>import</code> list.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
While we're working with templates, let's create a template for our
|
||||
<code>viewHandler</code> called <code>view.html</code>:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
!htmlify.bin < view.html
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Modify <code>viewHandler</code> accordingly:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
!srcextract.bin -src=final-noerror.go -name=viewHandler
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Notice that we've used almost exactly the same templating code in both
|
||||
handlers. Let's remove this duplication by moving the templating code
|
||||
to its own function:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
!srcextract.bin -src=final-template.go -name=viewHandler
|
||||
|
||||
!srcextract.bin -src=final-template.go -name=editHandler
|
||||
|
||||
!srcextract.bin -src=final-template.go -name=renderTemplate
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The handlers are now shorter and simpler.
|
||||
</p>
|
||||
|
||||
<h2>Handling non-existent pages</h2>
|
||||
|
||||
<p>
|
||||
What if you visit <code>/view/APageThatDoesntExist</code>? The program will
|
||||
crash. This is because it ignores the error return value from
|
||||
<code>loadPage</code>. Instead, if the requested Page doesn't exist, it should
|
||||
redirect the client to the edit Page so the content may be created:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
!srcextract.bin -src=final-noclosure.go -name=viewHandler
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The <code>http.Redirect</code> function adds an HTTP status code of
|
||||
<code>http.StatusFound</code> (302) and a <code>Location</code>
|
||||
header to the HTTP response.
|
||||
</p>
|
||||
|
||||
<h2>Saving Pages</h2>
|
||||
|
||||
<p>
|
||||
The function <code>saveHandler</code> will handle the form submission.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
!srcextract.bin -src=final-template.go -name=saveHandler
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The page title (provided in the URL) and the form's only field,
|
||||
<code>Body</code>, are stored in a new <code>Page</code>.
|
||||
The <code>save()</code> method is then called to write the data to a file,
|
||||
and the client is redirected to the <code>/view/</code> page.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The value returned by <code>FormValue</code> is of type <code>string</code>.
|
||||
We must convert that value to <code>[]byte</code> before it will fit into
|
||||
the <code>Page</code> struct. We use <code>[]byte(body)</code> to perform
|
||||
the conversion.
|
||||
</p>
|
||||
|
||||
<h2>Error handling</h2>
|
||||
|
||||
<p>
|
||||
There are several places in our program where errors are being ignored. This
|
||||
is bad practice, not least because when an error does occur the program will
|
||||
crash. A better solution is to handle the errors and return an error message
|
||||
to the user. That way if something does go wrong, the server will continue to
|
||||
function and the user will be notified.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
First, let's handle the errors in <code>renderTemplate</code>:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
!srcextract.bin -src=final-parsetemplate.go -name=renderTemplate
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The <code>http.Error</code> function sends a specified HTTP response code
|
||||
(in this case "Internal Server Error") and error message.
|
||||
Already the decision to put this in a separate function is paying off.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Now let's fix up <code>saveHandler</code>:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
!srcextract.bin -src=final-noclosure.go -name=saveHandler
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Any errors that occur during <code>p.save()</code> will be reported
|
||||
to the user.
|
||||
</p>
|
||||
|
||||
<h2>Template caching</h2>
|
||||
|
||||
<p>
|
||||
There is an inefficiency in this code: <code>renderTemplate</code> calls
|
||||
<code>ParseFile</code> every time a page is rendered.
|
||||
A better approach would be to call <code>ParseFile</code> once for each
|
||||
template at program initialization, and store the resultant
|
||||
<code>*Template</code> values in a data structure for later use.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
First we create a global map named <code>templates</code> in which to store
|
||||
our <code>*Template</code> values, keyed by <code>string</code>
|
||||
(the template name):
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
!srcextract.bin -src=final.go -name=templates
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Then we create an <code>init</code> function, which will be called before
|
||||
<code>main</code> at program initialization. The function
|
||||
<code>template.MustParseFile</code> is a convenience wrapper around
|
||||
<code>ParseFile</code> that does not return an error code; instead, it panics
|
||||
if an error is encountered. A panic is appropriate here; if the templates can't
|
||||
be loaded the only sensible thing to do is exit the program.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
!srcextract.bin -src=final.go -name=init
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
A <code>for</code> loop is used with a <code>range</code> statement to iterate
|
||||
over an array constant containing the names of the templates we want parsed.
|
||||
If we were to add more templates to our program, we would add their names to
|
||||
that array.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
We then modify our <code>renderTemplate</code> function to call
|
||||
the <code>Execute</code> method on the appropriate <code>Template</code> from
|
||||
<code>templates</code>:
|
||||
|
||||
<pre>
|
||||
!srcextract.bin -src=final.go -name=renderTemplate
|
||||
</pre>
|
||||
|
||||
<h2>Validation</h2>
|
||||
|
||||
<p>
|
||||
As you may have observed, this program has a serious security flaw: a user
|
||||
can supply an arbitrary path to be read/written on the server. To mitigate
|
||||
this, we can write a function to validate the title with a regular expression.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
First, add <code>"regexp"</code> to the <code>import</code> list.
|
||||
Then we can create a global variable to store our validation regexp:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
!srcextract.bin -src=final-noclosure.go -name=titleValidator
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The function <code>regexp.MustCompile</code> will parse and compile the
|
||||
regular expression, and return a <code>regexp.Regexp</code>.
|
||||
<code>MustCompile</code>, like <code>template.MustParseFile</code>,
|
||||
is distinct from <code>Compile</code> in that it will panic if
|
||||
the expression compilation fails, while <code>Compile</code> returns an
|
||||
<code>os.Error</code> as a second parameter.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Now, let's write a function that extracts the title string from the request
|
||||
URL, and tests it against our <code>TitleValidator</code> expression:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
!srcextract.bin -src=final-noclosure.go -name=getTitle
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
If the title is valid, it will be returned along with a <code>nil</code>
|
||||
error value. If the title is invalid, the function will write a
|
||||
"404 Not Found" error to the HTTP connection, and return an error to the
|
||||
handler.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Let's put a call to <code>getTitle</code> in each of the handlers:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
!srcextract.bin -src=final-noclosure.go -name=viewHandler
|
||||
|
||||
!srcextract.bin -src=final-noclosure.go -name=editHandler
|
||||
|
||||
!srcextract.bin -src=final-noclosure.go -name=saveHandler
|
||||
</pre>
|
||||
|
||||
<h2>Introducing Function Literals and Closures</h2>
|
||||
|
||||
<p>
|
||||
Catching the error condition in each handler introduces a lot of repeated code.
|
||||
What if we could wrap each of the handlers in a function that does this
|
||||
validation and error checking? Go's
|
||||
<a href="http://golang.org/doc/go_spec.html#Function_declarations">function
|
||||
literals</a> provide a powerful means of abstracting functionality
|
||||
that can help us here.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
First, we re-write the function definition of each of the handlers to accept
|
||||
a title string:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
func viewHandler(w http.ResponseWriter, r *http.Request, title string)
|
||||
func editHandler(w http.ResponseWriter, r *http.Request, title string)
|
||||
func saveHandler(w http.ResponseWriter, r *http.Request, title string)
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Now let's define a wrapper function that <i>takes a function of the above
|
||||
type</i>, and returns a function of type <code>http.HandlerFunc</code>
|
||||
(suitable to be passed to the function <code>http.HandleFunc</code>):
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
func makeHandler(fn func (http.ResponseWriter, *http.Request, string)) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
// Here we will extract the page title from the Request,
|
||||
// and call the provided handler 'fn'
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The returned function is called a closure because it encloses values defined
|
||||
outside of it. In this case, the variable <code>fn</code> (the single argument
|
||||
to <code>makeHandler</code>) is enclosed by the closure. The variable
|
||||
<code>fn</code> will be one of our save, edit, or view handlers.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Now we can take the code from <code>getTitle</code> and use it here
|
||||
(with some minor modifications):
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
!srcextract.bin -src=final.go -name=makeHandler
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The closure returned by <code>makeHandler</code> is a function that takes
|
||||
an <code>http.ResponseWriter</code> and <code>http.Request</code> (in other
|
||||
words, an <code>http.HandlerFunc</code>).
|
||||
The closure extracts the <code>title</code> from the request path, and
|
||||
validates it with the <code>TitleValidator</code> regexp. If the
|
||||
<code>title</code> is invalid, an error will be written to the
|
||||
<code>ResponseWriter</code> using the <code>http.NotFound</code> function.
|
||||
If the <code>title</code> is valid, the enclosed handler function
|
||||
<code>fn</code> will be called with the <code>ResponseWriter</code>,
|
||||
<code>Request</code>, and <code>title</code> as arguments.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Now we can wrap the handler functions with <code>makeHandler</code> in
|
||||
<code>main</code>, before they are registered with the <code>http</code>
|
||||
package:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
!srcextract.bin -src=final.go -name=main
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Finally we remove the calls to <code>getTitle</code> from the handler functions,
|
||||
making them much simpler:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
!srcextract.bin -src=final.go -name=viewHandler
|
||||
|
||||
!srcextract.bin -src=final.go -name=editHandler
|
||||
|
||||
!srcextract.bin -src=final.go -name=saveHandler
|
||||
</pre>
|
||||
|
||||
<h2>Try it out!</h2>
|
||||
|
||||
<p>
|
||||
<a href="final.go">Click here to view the final code listing.</a>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Recompile the code, and run the app:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
$ 8g wiki.go
|
||||
$ 8l wiki.8
|
||||
$ ./8.out
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Visiting <a href="http://localhost:8080/view/ANewPage">http://localhost:8080/view/ANewPage</a>
|
||||
should present you with the page edit form. You should then be able to
|
||||
enter some text, click 'Save', and be redirected to the newly created page.
|
||||
</p>
|
||||
|
||||
<h2>Other tasks</h2>
|
||||
|
||||
<p>
|
||||
Here are some simple tasks you might want to tackle on your own:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>Store templates in <code>tmpl/</code> and page data in <code>data/</code>.
|
||||
<li>Add a handler to make the web root redirect to
|
||||
<code>/view/FrontPage</code>.</li>
|
||||
<li>Spruce up the page templates by making them valid HTML and adding some
|
||||
CSS rules.</li>
|
||||
<li>Implement inter-page linking by converting instances of
|
||||
<code>[PageName]</code> to <br>
|
||||
<code><a href="/view/PageName">PageName</a></code>.
|
||||
(hint: you could use <code>regexp.ReplaceAllFunc</code> to do this)
|
||||
</li>
|
||||
</ul>
|
||||
113
doc/codereview_with_mq.html
Normal file
@@ -0,0 +1,113 @@
|
||||
<!-- Using Mercurial Queues with Codereview -->
|
||||
|
||||
<h2 id="Introduction">Introduction</h2>
|
||||
|
||||
<p>
|
||||
The Mercurial Queues extension (<code>mq</code>) provides a mechanism for
|
||||
managing patches on top of a Mercurial repository and is described in detail
|
||||
in Chapters
|
||||
<a href="http://hgbook.red-bean.com/read/managing-change-with-mercurial-queues.html">12</a>
|
||||
and <a href="http://hgbook.red-bean.com/read/advanced-uses-of-mercurial-queues.html">13</a>
|
||||
of <a href="http://hgbook.red-bean.com/read/">Mercurial: The Definitive Guide</a>.
|
||||
This document explains how to use <code>mq</code> in conjunction
|
||||
with the <code>codereview</code> Mercurial extension described in the
|
||||
instructions for <a href="contribute.html">contributing to the Go project</a>.
|
||||
It assumes you have read those instructions.
|
||||
</p>
|
||||
|
||||
<h2>Configuration</h2>
|
||||
|
||||
<p>
|
||||
To enable <code>mq</code> edit either <code>$HOME/.hgrc</code> (to enable it
|
||||
for all of your repositories) or <code>$GOROOT/.hg/hgrc</code> (to enable it for the
|
||||
repository at <code>$GOROOT</code>) to add:</p>
|
||||
|
||||
<pre>
|
||||
[extensions]
|
||||
mq=
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Since pulling, pushing, updating and committing while <code>mq</code> patches
|
||||
are applied can damage your repository or a remote one, add these lines to
|
||||
prevent that case:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
[hooks]
|
||||
# Prevent "hg pull" if MQ patches are applied.
|
||||
prechangegroup.mq-no-pull = ! hg qtop > /dev/null 2>&1
|
||||
# Prevent "hg push" if MQ patches are applied.
|
||||
preoutgoing.mq-no-push = ! hg qtop > /dev/null 2>&1
|
||||
# Prevent "hg update" if MQ patches are applied.
|
||||
preupdate.mq-no-update = ! hg qtop > /dev/null 2>&1
|
||||
</pre>
|
||||
|
||||
<h2>Making a change</h2>
|
||||
|
||||
<p>
|
||||
The entire checked-out tree is writable and you can use <code>mq</code>,
|
||||
as documented in Chapter
|
||||
<a href="http://hgbook.red-bean.com/read/managing-change-with-mercurial-queues.html">12</a>
|
||||
of "The Guide",
|
||||
to implement your change as a single patch or a series of patches.
|
||||
|
||||
</p>
|
||||
|
||||
<p>When you are ready to send a change out for review, run</p>
|
||||
|
||||
<pre>
|
||||
$ hg change
|
||||
</pre>
|
||||
|
||||
<p>from any directory in your Go repository with all of the <code>mq</code> patches relevant to your
|
||||
change applied and then proceed as instructed in <a href="contribute.html">contributing
|
||||
to the Go project</a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The change number reported by <code>hg change</code>, preceded by a <code>+</code>,
|
||||
can be used as an <code>mq</code> patch guard to assist in controlling which patches
|
||||
are applied as described in Chapter
|
||||
<a href="http://hgbook.red-bean.com/read/advanced-uses-of-mercurial-queues.html">13</a>
|
||||
of "The Guide".
|
||||
For example, the command:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
for p in $(hg qapplied); do hg qguard $p +99999; done
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
will apply the guard <code>+99999</code> guard to all currently applied <code>mq</code>
|
||||
patches.
|
||||
</p>
|
||||
|
||||
<h2>Synchronizing your client</h2>
|
||||
|
||||
<p>While you were working, others might have submitted changes
|
||||
to the repository and, as explained in <a href="contribute.html">contributing
|
||||
to the Go project</a>, it is necessary to synchronize your repository using
|
||||
<code>hg sync</code>before sending your change list for review.
|
||||
Because <code>hg sync</code> runs <code>hg pull -u</code>,
|
||||
you should not run <code>hg sync</code> while <code>mq</code> patches are
|
||||
applied. Instead
|
||||
pop all your patches before running <code>hg sync</code> and reapply them after
|
||||
it has completed.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
When reapplying the patches, you may need to resolve conflicts
|
||||
as described in <a href="contribute.html">contributing to the Go project</a>.
|
||||
</p>
|
||||
|
||||
<h2>Mailing the change for review</h2>
|
||||
|
||||
<p>
|
||||
You should have all of the <code>mq</code> patches relevant to your
|
||||
change applied when you run <code>hg mail</code>.
|
||||
|
||||
<h2>Submitting the change after the review</h2>
|
||||
|
||||
If you are a committer, you should have all of the <code>mq</code> patches relevant to your
|
||||
change applied when you run <code>hg commit</code>.
|
||||
@@ -296,8 +296,8 @@ CodewalkViewer.prototype.updateHeight = function() {
|
||||
this.sizer.height(codeHeight);
|
||||
};
|
||||
|
||||
window.initFuncs.push(function() {
|
||||
var viewer = new CodewalkViewer(jQuery('#codewalk-main'));
|
||||
jQuery(document).ready(function() {
|
||||
var viewer = new CodewalkViewer(jQuery());
|
||||
viewer.selectFirstComment();
|
||||
viewer.targetCommentLinksAtBlank();
|
||||
viewer.installEventHandlers();
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
its <code>src</code> is just a file name.
|
||||
</step>
|
||||
|
||||
<step title="Specifying a source line" src='doc/codewalk/codewalk.xml:/title="Title"/'>
|
||||
<step title="Specifiying a source line" src='doc/codewalk/codewalk.xml:/title="Title"/'>
|
||||
The most complex part of the codewalk specification is
|
||||
saying what lines to highlight.
|
||||
Instead of ordinary line numbers,
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
turn.
|
||||
</step>
|
||||
|
||||
<step title="Multiple return values" src="doc/codewalk/pig.go:/\/\/ roll returns/,/true\n}/">
|
||||
<step title="Multiple return values" src="doc/codewalk/pig.go:/\/\/ roll returns/,/stay.*true\n}/">
|
||||
Go functions can return multiple values.
|
||||
<br/><br/>
|
||||
|
||||
@@ -82,6 +82,16 @@
|
||||
associated with the current player.
|
||||
</step>
|
||||
|
||||
<step title="Comparing functions" src="doc/codewalk/pig.go:/if action/,/currentPlayer\)\)\n\t\t}/">
|
||||
Functions can be compared for equality in Go. From the
|
||||
<a href="http://golang.org/doc/go_spec.html#Comparison_operators">language specification</a>:
|
||||
Function values are equal if they refer to the same function or if both are <code>nil</code>.
|
||||
<br/><br/>
|
||||
|
||||
We enforce that a <code>strategy</code> function can only return a legal
|
||||
<code>action</code>: either <code>roll</code> or <code>stay</code>.
|
||||
</step>
|
||||
|
||||
<step title="Simulating a tournament" src="doc/codewalk/pig.go:/\/\/ roundRobin/,/gamesPerStrategy\n}/">
|
||||
The <code>roundRobin</code> function simulates a tournament and tallies wins.
|
||||
Each strategy plays each other strategy <code>gamesPerSeries</code> times.
|
||||
|
||||
@@ -1,130 +0,0 @@
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
/*
|
||||
Generating random text: a Markov chain algorithm
|
||||
|
||||
Based on the program presented in the "Design and Implementation" chapter
|
||||
of The Practice of Programming (Kernighan and Pike, Addison-Wesley 1999).
|
||||
See also Computer Recreations, Scientific American 260, 122 - 125 (1989).
|
||||
|
||||
A Markov chain algorithm generates text by creating a statistical model of
|
||||
potential textual suffixes for a given prefix. Consider this text:
|
||||
|
||||
I am not a number! I am a free man!
|
||||
|
||||
Our Markov chain algorithm would arrange this text into this set of prefixes
|
||||
and suffixes, or "chain": (This table assumes a prefix length of two words.)
|
||||
|
||||
Prefix Suffix
|
||||
|
||||
"" "" I
|
||||
"" I am
|
||||
I am a
|
||||
I am not
|
||||
a free man!
|
||||
am a free
|
||||
am not a
|
||||
a number! I
|
||||
number! I am
|
||||
not a number!
|
||||
|
||||
To generate text using this table we select an initial prefix ("I am", for
|
||||
example), choose one of the suffixes associated with that prefix at random
|
||||
with probability determined by the input statistics ("a"),
|
||||
and then create a new prefix by removing the first word from the prefix
|
||||
and appending the suffix (making the new prefix is "am a"). Repeat this process
|
||||
until we can't find any suffixes for the current prefix or we exceed the word
|
||||
limit. (The word limit is necessary as the chain table may contain cycles.)
|
||||
|
||||
Our version of this program reads text from standard input, parsing it into a
|
||||
Markov chain, and writes generated text to standard output.
|
||||
The prefix and output lengths can be specified using the -prefix and -words
|
||||
flags on the command-line.
|
||||
*/
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/rand"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Prefix is a Markov chain prefix of one or more words.
|
||||
type Prefix []string
|
||||
|
||||
// String returns the Prefix as a string (for use as a map key).
|
||||
func (p Prefix) String() string {
|
||||
return strings.Join(p, " ")
|
||||
}
|
||||
|
||||
// Shift removes the first word from the Prefix and appends the given word.
|
||||
func (p Prefix) Shift(word string) {
|
||||
copy(p, p[1:])
|
||||
p[len(p)-1] = word
|
||||
}
|
||||
|
||||
// Chain contains a map ("chain") of prefixes to a list of suffixes.
|
||||
// A prefix is a string of prefixLen words joined with spaces.
|
||||
// A suffix is a single word. A prefix can have multiple suffixes.
|
||||
type Chain struct {
|
||||
chain map[string][]string
|
||||
prefixLen int
|
||||
}
|
||||
|
||||
// NewChain returns a new Chain with prefixes of prefixLen words.
|
||||
func NewChain(prefixLen int) *Chain {
|
||||
return &Chain{make(map[string][]string), prefixLen}
|
||||
}
|
||||
|
||||
// Build reads text from the provided Reader and
|
||||
// parses it into prefixes and suffixes that are stored in Chain.
|
||||
func (c *Chain) Build(r io.Reader) {
|
||||
br := bufio.NewReader(r)
|
||||
p := make(Prefix, c.prefixLen)
|
||||
for {
|
||||
var s string
|
||||
if _, err := fmt.Fscan(br, &s); err != nil {
|
||||
break
|
||||
}
|
||||
key := p.String()
|
||||
c.chain[key] = append(c.chain[key], s)
|
||||
p.Shift(s)
|
||||
}
|
||||
}
|
||||
|
||||
// Generate returns a string of at most n words generated from Chain.
|
||||
func (c *Chain) Generate(n int) string {
|
||||
p := make(Prefix, c.prefixLen)
|
||||
var words []string
|
||||
for i := 0; i < n; i++ {
|
||||
choices := c.chain[p.String()]
|
||||
if len(choices) == 0 {
|
||||
break
|
||||
}
|
||||
next := choices[rand.Intn(len(choices))]
|
||||
words = append(words, next)
|
||||
p.Shift(next)
|
||||
}
|
||||
return strings.Join(words, " ")
|
||||
}
|
||||
|
||||
func main() {
|
||||
// Register command-line flags.
|
||||
numWords := flag.Int("words", 100, "maximum number of words to print")
|
||||
prefixLen := flag.Int("prefix", 2, "prefix length in words")
|
||||
|
||||
flag.Parse() // Parse command-line flags.
|
||||
rand.Seed(time.Now().UnixNano()) // Seed the random number generator.
|
||||
|
||||
c := NewChain(*prefixLen) // Initialize a new Chain.
|
||||
c.Build(os.Stdin) // Build chains from standard input.
|
||||
text := c.Generate(*numWords) // Generate text.
|
||||
fmt.Println(text) // Write text to standard output.
|
||||
}
|
||||
@@ -1,307 +0,0 @@
|
||||
<!--
|
||||
Copyright 2011 The Go Authors. All rights reserved.
|
||||
Use of this source code is governed by a BSD-style
|
||||
license that can be found in the LICENSE file.
|
||||
-->
|
||||
|
||||
<codewalk title="Generating arbitrary text: a Markov chain algorithm">
|
||||
|
||||
<step title="Introduction" src="doc/codewalk/markov.go:/Generating/,/line\./">
|
||||
This codewalk describes a program that generates random text using
|
||||
a Markov chain algorithm. The package comment describes the algorithm
|
||||
and the operation of the program. Please read it before continuing.
|
||||
</step>
|
||||
|
||||
<step title="Modeling Markov chains" src="doc/codewalk/markov.go:/ chain/">
|
||||
A chain consists of a prefix and a suffix. Each prefix is a set
|
||||
number of words, while a suffix is a single word.
|
||||
A prefix can have an arbitrary number of suffixes.
|
||||
To model this data, we use a <code>map[string][]string</code>.
|
||||
Each map key is a prefix (a <code>string</code>) and its values are
|
||||
lists of suffixes (a slice of strings, <code>[]string</code>).
|
||||
<br/><br/>
|
||||
Here is the example table from the package comment
|
||||
as modeled by this data structure:
|
||||
<pre>
|
||||
map[string][]string{
|
||||
" ": {"I"},
|
||||
" I": {"am"},
|
||||
"I am": {"a", "not"},
|
||||
"a free": {"man!"},
|
||||
"am a": {"free"},
|
||||
"am not": {"a"},
|
||||
"a number!": {"I"},
|
||||
"number! I": {"am"},
|
||||
"not a": {"number!"},
|
||||
}</pre>
|
||||
While each prefix consists of multiple words, we
|
||||
store prefixes in the map as a single <code>string</code>.
|
||||
It would seem more natural to store the prefix as a
|
||||
<code>[]string</code>, but we can't do this with a map because the
|
||||
key type of a map must implement equality (and slices do not).
|
||||
<br/><br/>
|
||||
Therefore, in most of our code we will model prefixes as a
|
||||
<code>[]string</code> and join the strings together with a space
|
||||
to generate the map key:
|
||||
<pre>
|
||||
Prefix Map key
|
||||
|
||||
[]string{"", ""} " "
|
||||
[]string{"", "I"} " I"
|
||||
[]string{"I", "am"} "I am"
|
||||
</pre>
|
||||
</step>
|
||||
|
||||
<step title="The Chain struct" src="doc/codewalk/markov.go:/type Chain/,/}/">
|
||||
The complete state of the chain table consists of the table itself and
|
||||
the word length of the prefixes. The <code>Chain</code> struct stores
|
||||
this data.
|
||||
</step>
|
||||
|
||||
<step title="The NewChain constructor function" src="doc/codewalk/markov.go:/func New/,/\n}/">
|
||||
The <code>Chain</code> struct has two unexported fields (those that
|
||||
do not begin with an upper case character), and so we write a
|
||||
<code>NewChain</code> constructor function that initializes the
|
||||
<code>chain</code> map with <code>make</code> and sets the
|
||||
<code>prefixLen</code> field.
|
||||
<br/><br/>
|
||||
This is constructor function is not strictly necessary as this entire
|
||||
program is within a single package (<code>main</code>) and therefore
|
||||
there is little practical difference between exported and unexported
|
||||
fields. We could just as easily write out the contents of this function
|
||||
when we want to construct a new Chain.
|
||||
But using these unexported fields is good practice; it clearly denotes
|
||||
that only methods of Chain and its constructor function should access
|
||||
those fields. Also, structuring <code>Chain</code> like this means we
|
||||
could easily move it into its own package at some later date.
|
||||
</step>
|
||||
|
||||
<step title="The Prefix type" src="doc/codewalk/markov.go:/type Prefix/">
|
||||
Since we'll be working with prefixes often, we define a
|
||||
<code>Prefix</code> type with the concrete type <code>[]string</code>.
|
||||
Defining a named type clearly allows us to be explicit when we are
|
||||
working with a prefix instead of just a <code>[]string</code>.
|
||||
Also, in Go we can define methods on any named type (not just structs),
|
||||
so we can add methods that operate on <code>Prefix</code> if we need to.
|
||||
</step>
|
||||
|
||||
<step title="The String method" src="doc/codewalk/markov.go:/func[^\n]+String/,/}/">
|
||||
The first method we define on <code>Prefix</code> is
|
||||
<code>String</code>. It returns a <code>string</code> representation
|
||||
of a <code>Prefix</code> by joining the slice elements together with
|
||||
spaces. We will use this method to generate keys when working with
|
||||
the chain map.
|
||||
</step>
|
||||
|
||||
<step title="Building the chain" src="doc/codewalk/markov.go:/func[^\n]+Build/,/\n}/">
|
||||
The <code>Build</code> method reads text from an <code>io.Reader</code>
|
||||
and parses it into prefixes and suffixes that are stored in the
|
||||
<code>Chain</code>.
|
||||
<br/><br/>
|
||||
The <code><a href="/pkg/io/#Reader">io.Reader</a></code> is an
|
||||
interface type that is widely used by the standard library and
|
||||
other Go code. Our code uses the
|
||||
<code><a href="/pkg/fmt/#Fscan">fmt.Fscan</a></code> function, which
|
||||
reads space-separated values from an <code>io.Reader</code>.
|
||||
<br/><br/>
|
||||
The <code>Build</code> method returns once the <code>Reader</code>'s
|
||||
<code>Read</code> method returns <code>io.EOF</code> (end of file)
|
||||
or some other read error occurs.
|
||||
</step>
|
||||
|
||||
<step title="Buffering the input" src="doc/codewalk/markov.go:/bufio\.NewReader/">
|
||||
This function does many small reads, which can be inefficient for some
|
||||
<code>Readers</code>. For efficiency we wrap the provided
|
||||
<code>io.Reader</code> with
|
||||
<code><a href="/pkg/bufio/">bufio.NewReader</a></code> to create a
|
||||
new <code>io.Reader</code> that provides buffering.
|
||||
</step>
|
||||
|
||||
<step title="The Prefix variable" src="doc/codewalk/markov.go:/make\(Prefix/">
|
||||
At the top of the function we make a <code>Prefix</code> slice
|
||||
<code>p</code> using the <code>Chain</code>'s <code>prefixLen</code>
|
||||
field as its length.
|
||||
We'll use this variable to hold the current prefix and mutate it with
|
||||
each new word we encounter.
|
||||
</step>
|
||||
|
||||
<step title="Scanning words" src="doc/codewalk/markov.go:/var s string/,/\n }/">
|
||||
In our loop we read words from the <code>Reader</code> into a
|
||||
<code>string</code> variable <code>s</code> using
|
||||
<code>fmt.Fscan</code>. Since <code>Fscan</code> uses space to
|
||||
separate each input value, each call will yield just one word
|
||||
(including punctuation), which is exactly what we need.
|
||||
<br/><br/>
|
||||
<code>Fscan</code> returns an error if it encounters a read error
|
||||
(<code>io.EOF</code>, for example) or if it can't scan the requested
|
||||
value (in our case, a single string). In either case we just want to
|
||||
stop scanning, so we <code>break</code> out of the loop.
|
||||
</step>
|
||||
|
||||
<step title="Adding a prefix and suffix to the chain" src="doc/codewalk/markov.go:/ key/,/key\], s\)">
|
||||
The word stored in <code>s</code> is a new suffix. We add the new
|
||||
prefix/suffix combination to the <code>chain</code> map by computing
|
||||
the map key with <code>p.String</code> and appending the suffix
|
||||
to the slice stored under that key.
|
||||
<br/><br/>
|
||||
The built-in <code>append</code> function appends elements to a slice
|
||||
and allocates new storage when necessary. When the provided slice is
|
||||
<code>nil</code>, <code>append</code> allocates a new slice.
|
||||
This behavior conveniently ties in with the semantics of our map:
|
||||
retrieving an unset key returns the zero value of the value type and
|
||||
the zero value of <code>[]string</code> is <code>nil</code>.
|
||||
When our program encounters a new prefix (yielding a <code>nil</code>
|
||||
value in the map) <code>append</code> will allocate a new slice.
|
||||
<br/><br/>
|
||||
For more information about the <code>append</code> function and slices
|
||||
in general see the
|
||||
<a href="/doc/articles/slices_usage_and_internals.html">Slices: usage and internals</a> article.
|
||||
</step>
|
||||
|
||||
<step title="Pushing the suffix onto the prefix" src="doc/codewalk/markov.go:/p\.Shift/">
|
||||
Before reading the next word our algorithm requires us to drop the
|
||||
first word from the prefix and push the current suffix onto the prefix.
|
||||
<br/><br/>
|
||||
When in this state
|
||||
<pre>
|
||||
p == Prefix{"I", "am"}
|
||||
s == "not" </pre>
|
||||
the new value for <code>p</code> would be
|
||||
<pre>
|
||||
p == Prefix{"am", "not"}</pre>
|
||||
This operation is also required during text generation so we put
|
||||
the code to perform this mutation of the slice inside a method on
|
||||
<code>Prefix</code> named <code>Shift</code>.
|
||||
</step>
|
||||
|
||||
<step title="The Shift method" src="doc/codewalk/markov.go:/func[^\n]+Shift/,/\n}/">
|
||||
The <code>Shift</code> method uses the built-in <code>copy</code>
|
||||
function to copy the last len(p)-1 elements of <code>p</code> to
|
||||
the start of the slice, effectively moving the elements
|
||||
one index to the left (if you consider zero as the leftmost index).
|
||||
<pre>
|
||||
p := Prefix{"I", "am"}
|
||||
copy(p, p[1:])
|
||||
// p == Prefix{"am", "am"}</pre>
|
||||
We then assign the provided <code>word</code> to the last index
|
||||
of the slice:
|
||||
<pre>
|
||||
// suffix == "not"
|
||||
p[len(p)-1] = suffix
|
||||
// p == Prefix{"am", "not"}</pre>
|
||||
</step>
|
||||
|
||||
<step title="Generating text" src="doc/codewalk/markov.go:/func[^\n]+Generate/,/\n}/">
|
||||
The <code>Generate</code> method is similar to <code>Build</code>
|
||||
except that instead of reading words from a <code>Reader</code>
|
||||
and storing them in a map, it reads words from the map and
|
||||
appends them to a slice (<code>words</code>).
|
||||
<br/><br/>
|
||||
<code>Generate</code> uses a conditional for loop to generate
|
||||
up to <code>n</code> words.
|
||||
</step>
|
||||
|
||||
<step title="Getting potential suffixes" src="doc/codewalk/markov.go:/choices/,/}\n/">
|
||||
At each iteration of the loop we retrieve a list of potential suffixes
|
||||
for the current prefix. We access the <code>chain</code> map at key
|
||||
<code>p.String()</code> and assign its contents to <code>choices</code>.
|
||||
<br/><br/>
|
||||
If <code>len(choices)</code> is zero we break out of the loop as there
|
||||
are no potential suffixes for that prefix.
|
||||
This test also works if the key isn't present in the map at all:
|
||||
in that case, <code>choices</code> will be <code>nil</code> and the
|
||||
length of a <code>nil</code> slice is zero.
|
||||
</step>
|
||||
|
||||
<step title="Choosing a suffix at random" src="doc/codewalk/markov.go:/next := choices/,/Shift/">
|
||||
To choose a suffix we use the
|
||||
<code><a href="/pkg/math/rand/#Intn">rand.Intn</a></code> function.
|
||||
It returns a random integer up to (but not including) the provided
|
||||
value. Passing in <code>len(choices)</code> gives us a random index
|
||||
into the full length of the list.
|
||||
<br/><br/>
|
||||
We use that index to pick our new suffix, assign it to
|
||||
<code>next</code> and append it to the <code>words</code> slice.
|
||||
<br/><br/>
|
||||
Next, we <code>Shift</code> the new suffix onto the prefix just as
|
||||
we did in the <code>Build</code> method.
|
||||
</step>
|
||||
|
||||
<step title="Returning the generated text" src="doc/codewalk/markov.go:/Join\(words/">
|
||||
Before returning the generated text as a string, we use the
|
||||
<code>strings.Join</code> function to join the elements of
|
||||
the <code>words</code> slice together, separated by spaces.
|
||||
</step>
|
||||
|
||||
<step title="Command-line flags" src="doc/codewalk/markov.go:/Register command-line flags/,/prefixLen/">
|
||||
To make it easy to tweak the prefix and generated text lengths we
|
||||
use the <code><a href="/pkg/flag/">flag</a></code> package to parse
|
||||
command-line flags.
|
||||
<br/><br/>
|
||||
These calls to <code>flag.Int</code> register new flags with the
|
||||
<code>flag</code> package. The arguments to <code>Int</code> are the
|
||||
flag name, its default value, and a description. The <code>Int</code>
|
||||
function returns a pointer to an integer that will contain the
|
||||
user-supplied value (or the default value if the flag was omitted on
|
||||
the command-line).
|
||||
</step>
|
||||
|
||||
<step title="Program set up" src="doc/codewalk/markov.go:/flag.Parse/,/rand.Seed/">
|
||||
The <code>main</code> function begins by parsing the command-line
|
||||
flags with <code>flag.Parse</code> and seeding the <code>rand</code>
|
||||
package's random number generator with the current time.
|
||||
<br/><br/>
|
||||
If the command-line flags provided by the user are invalid the
|
||||
<code>flag.Parse</code> function will print an informative usage
|
||||
message and terminate the program.
|
||||
</step>
|
||||
|
||||
<step title="Creating and building a new Chain" src="doc/codewalk/markov.go:/c := NewChain/,/c\.Build/">
|
||||
To create the new <code>Chain</code> we call <code>NewChain</code>
|
||||
with the value of the <code>prefix</code> flag.
|
||||
<br/><br/>
|
||||
To build the chain we call <code>Build</code> with
|
||||
<code>os.Stdin</code> (which implements <code>io.Reader</code>) so
|
||||
that it will read its input from standard input.
|
||||
</step>
|
||||
|
||||
<step title="Generating and printing text" src="doc/codewalk/markov.go:/c\.Generate/,/fmt.Println/">
|
||||
Finally, to generate text we call <code>Generate</code> with
|
||||
the value of the <code>words</code> flag and assigning the result
|
||||
to the variable <code>text</code>.
|
||||
<br/><br/>
|
||||
Then we call <code>fmt.Println</code> to write the text to standard
|
||||
output, followed by a carriage return.
|
||||
</step>
|
||||
|
||||
<step title="Using this program" src="doc/codewalk/markov.go">
|
||||
To use this program, first build it with the
|
||||
<a href="/cmd/go/">go</a> command:
|
||||
<pre>
|
||||
$ go build markov.go</pre>
|
||||
And then execute it while piping in some input text:
|
||||
<pre>
|
||||
$ echo "a man a plan a canal panama" \
|
||||
| ./markov -prefix=1
|
||||
a plan a man a plan a canal panama</pre>
|
||||
Here's a transcript of generating some text using the Go distribution's
|
||||
README file as source material:
|
||||
<pre>
|
||||
$ ./markov -words=10 < $GOROOT/README
|
||||
This is the source code repository for the Go source
|
||||
$ ./markov -prefix=1 -words=10 < $GOROOT/README
|
||||
This is the go directory (the one containing this README).
|
||||
$ ./markov -prefix=1 -words=10 < $GOROOT/README
|
||||
This is the variable if you have just untarred a</pre>
|
||||
</step>
|
||||
|
||||
<step title="An exercise for the reader" src="doc/codewalk/markov.go">
|
||||
The <code>Generate</code> function does a lot of allocations when it
|
||||
builds the <code>words</code> slice. As an exercise, modify it to
|
||||
take an <code>io.Writer</code> to which it incrementally writes the
|
||||
generated text with <code>Fprint</code>.
|
||||
Aside from being more efficient this makes <code>Generate</code>
|
||||
more symmetrical to <code>Build</code>.
|
||||
</step>
|
||||
|
||||
</codewalk>
|
||||
@@ -6,7 +6,7 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"rand"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -23,7 +23,7 @@ type score struct {
|
||||
// An action transitions stochastically to a resulting score.
|
||||
type action func(current score) (result score, turnIsOver bool)
|
||||
|
||||
// roll returns the (result, turnIsOver) outcome of simulating a die roll.
|
||||
// roll returns the (result, turnIsOver) outcome of simulating a die roll.
|
||||
// If the roll value is 1, then thisTurn score is abandoned, and the players'
|
||||
// roles swap. Otherwise, the roll value is added to thisTurn.
|
||||
func roll(s score) (score, bool) {
|
||||
@@ -61,6 +61,9 @@ func play(strategy0, strategy1 strategy) int {
|
||||
currentPlayer := rand.Intn(2) // Randomly decide who plays first
|
||||
for s.player+s.thisTurn < win {
|
||||
action := strategies[currentPlayer](s)
|
||||
if action != roll && action != stay {
|
||||
panic(fmt.Sprintf("Player %d is cheating", currentPlayer))
|
||||
}
|
||||
s, turnIsOver = action(s)
|
||||
if turnIsOver {
|
||||
currentPlayer = (currentPlayer + 1) % 2
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
# Copyright 2013 The Go Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style
|
||||
# license that can be found in the LICENSE file.
|
||||
|
||||
set -e
|
||||
|
||||
function fail {
|
||||
echo FAIL: doc/codewalk/$1
|
||||
exit 1
|
||||
}
|
||||
|
||||
# markov.xml
|
||||
echo foo | go run markov.go | grep foo > /dev/null || fail markov
|
||||
|
||||
# functions.xml
|
||||
go run pig.go | grep 'Wins, losses staying at k = 100: 210/990 (21.2%), 780/990 (78.8%)' > /dev/null || fail pig
|
||||
|
||||
# sharemem.xml: only build the example, as it uses the network
|
||||
go build urlpoll.go || fail urlpoll
|
||||
rm -f urlpoll
|
||||
@@ -65,7 +65,7 @@ and then loops passing completed Resources back to the pending
|
||||
channel after appropriate delays.
|
||||
</step>
|
||||
|
||||
<step title="Creating channels" src="doc/codewalk/urlpoll.go:/Create our/,/complete/">
|
||||
<step title="Creating channels" src="doc/codewalk/urlpoll.go:/create our/,/complete/">
|
||||
First, main makes two channels of *Resource, pending and complete.
|
||||
<br/><br/>
|
||||
Inside main, a new goroutine sends one Resource per URL to pending
|
||||
@@ -75,7 +75,7 @@ The pending and complete channels are passed to each of the Poller
|
||||
goroutines, within which they are known as in and out.
|
||||
</step>
|
||||
|
||||
<step title="Initializing StateMonitor" src="doc/codewalk/urlpoll.go:/Launch the StateMonitor/,/statusInterval/">
|
||||
<step title="Initializing StateMonitor" src="doc/codewalk/urlpoll.go:/launch the StateMonitor/,/statusInterval/">
|
||||
StateMonitor will initialize and launch a goroutine that stores the state
|
||||
of each Resource. We will look at this function in detail later.
|
||||
<br/><br/>
|
||||
@@ -83,14 +83,14 @@ For now, the important thing to note is that it returns a channel of State,
|
||||
which is saved as status and passed to the Poller goroutines.
|
||||
</step>
|
||||
|
||||
<step title="Launching Poller goroutines" src="doc/codewalk/urlpoll.go:/Launch some Poller/,/}/">
|
||||
<step title="Launching Poller goroutines" src="doc/codewalk/urlpoll.go:/launch some Poller/,/}/">
|
||||
Now that it has the necessary channels, main launches a number of
|
||||
Poller goroutines, passing the channels as arguments.
|
||||
The channels provide the means of communication between the main, Poller, and
|
||||
StateMonitor goroutines.
|
||||
</step>
|
||||
|
||||
<step title="Send Resources to pending" src="doc/codewalk/urlpoll.go:/Send some Resources/,/}\(\)/">
|
||||
<step title="Send Resources to pending" src="doc/codewalk/urlpoll.go:/send some Resources/,/}\(\)/">
|
||||
To add the initial work to the system, main starts a new goroutine
|
||||
that allocates and sends one Resource per URL to pending.
|
||||
<br/><br/>
|
||||
@@ -171,7 +171,7 @@ and/or writes to a shared map.
|
||||
|
||||
<step title="Conclusion" src="doc/codewalk/urlpoll.go">
|
||||
In this codewalk we have explored a simple example of using Go's concurrency
|
||||
primitives to share memory through communication.
|
||||
primitives to share memory through commmunication.
|
||||
<br/><br/>
|
||||
This should provide a starting point from which to explore the ways in which
|
||||
goroutines and channels can be used to write expressive and concise concurrent
|
||||
|
||||
@@ -5,16 +5,17 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"http"
|
||||
"log"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
numPollers = 2 // number of Poller goroutines to launch
|
||||
pollInterval = 60 * time.Second // how often to poll each URL
|
||||
statusInterval = 10 * time.Second // how often to log status to stdout
|
||||
errTimeout = 10 * time.Second // back-off timeout on error
|
||||
numPollers = 2 // number of Poller goroutines to launch
|
||||
second = 1e9 // one second is 1e9 nanoseconds
|
||||
pollInterval = 60 * second // how often to poll each URL
|
||||
statusInterval = 10 * second // how often to log status to stdout
|
||||
errTimeout = 10 * second // back-off timeout on error
|
||||
)
|
||||
|
||||
var urls = []string{
|
||||
@@ -32,7 +33,7 @@ type State struct {
|
||||
// StateMonitor maintains a map that stores the state of the URLs being
|
||||
// polled, and prints the current state every updateInterval nanoseconds.
|
||||
// It returns a chan State to which resource state should be sent.
|
||||
func StateMonitor(updateInterval time.Duration) chan<- State {
|
||||
func StateMonitor(updateInterval int64) chan<- State {
|
||||
updates := make(chan State)
|
||||
urlStatus := make(map[string]string)
|
||||
ticker := time.NewTicker(updateInterval)
|
||||
@@ -60,7 +61,7 @@ func logState(s map[string]string) {
|
||||
// Resource represents an HTTP URL to be polled by this program.
|
||||
type Resource struct {
|
||||
url string
|
||||
errCount int
|
||||
errCount int64
|
||||
}
|
||||
|
||||
// Poll executes an HTTP HEAD request for url
|
||||
@@ -70,16 +71,16 @@ func (r *Resource) Poll() string {
|
||||
if err != nil {
|
||||
log.Println("Error", r.url, err)
|
||||
r.errCount++
|
||||
return err.Error()
|
||||
return err.String()
|
||||
}
|
||||
r.errCount = 0
|
||||
return resp.Status
|
||||
}
|
||||
|
||||
// Sleep sleeps for an appropriate interval (dependent on error state)
|
||||
// Sleep sleeps for an appropriate interval (dependant on error state)
|
||||
// before sending the Resource to done.
|
||||
func (r *Resource) Sleep(done chan<- *Resource) {
|
||||
time.Sleep(pollInterval + errTimeout*time.Duration(r.errCount))
|
||||
func (r *Resource) Sleep(done chan *Resource) {
|
||||
time.Sleep(pollInterval + errTimeout*r.errCount)
|
||||
done <- r
|
||||
}
|
||||
|
||||
@@ -92,18 +93,18 @@ func Poller(in <-chan *Resource, out chan<- *Resource, status chan<- State) {
|
||||
}
|
||||
|
||||
func main() {
|
||||
// Create our input and output channels.
|
||||
// create our input and output channels
|
||||
pending, complete := make(chan *Resource), make(chan *Resource)
|
||||
|
||||
// Launch the StateMonitor.
|
||||
// launch the StateMonitor
|
||||
status := StateMonitor(statusInterval)
|
||||
|
||||
// Launch some Poller goroutines.
|
||||
// launch some Poller goroutines
|
||||
for i := 0; i < numPollers; i++ {
|
||||
go Poller(pending, complete, status)
|
||||
}
|
||||
|
||||
// Send some Resources to the pending queue.
|
||||
// send some Resources to the pending queue
|
||||
go func() {
|
||||
for _, url := range urls {
|
||||
pending <- &Resource{url: url}
|
||||
|
||||
53
doc/community.html
Normal file
@@ -0,0 +1,53 @@
|
||||
<!-- title Community -->
|
||||
|
||||
<div class="left-column">
|
||||
|
||||
<h2 id="developer_info">The Go Community</h2>
|
||||
|
||||
<h3 id="mailinglist"><a href="http://groups.google.com/group/golang-nuts">Go Nuts Mailing List</a></h3>
|
||||
<p>The <a href="http://groups.google.com/group/golang-nuts">golang-nuts</a>
|
||||
mailing list is for general Go discussion.</p>
|
||||
|
||||
<h3 id=""><a href="http://godashboard.appspot.com/package">Go Packages Dashboard</a></h3>
|
||||
<p>A list of the most popular <a href="/cmd/goinstall/">goinstall</a>'d
|
||||
Go libraries.</p>
|
||||
|
||||
<h3 id=""><a href="http://godashboard.appspot.com/project">Go Project Dashboard</a></h3>
|
||||
<p>A list of external Go projects including programs and libraries.</p>
|
||||
|
||||
<h3 id="irc"><a href="irc:irc.freenode.net/go-nuts">Go IRC Channel</a></h3>
|
||||
<p><b>#go-nuts</b> on <b>irc.freenode.net</b> is the official Go IRC channel.</p>
|
||||
|
||||
<h3 id="twitter"><a href="http://twitter.com/go_nuts">@go_nuts at Twitter</a></h3>
|
||||
<p>The Go project's official Twitter account.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="right-column">
|
||||
|
||||
<h2 id="blogs">Blogs</h2>
|
||||
|
||||
<h3 id="blog_go"><a href="http://blog.golang.org/">The Go Blog</a></h3>
|
||||
<p>
|
||||
The Go project's official blog, maintained by the core Go developers.
|
||||
</p>
|
||||
|
||||
<h3 id="blog_rsc"><a href="http://research.swtch.com/search/label/Go">research!rsc</a></h3>
|
||||
<p>
|
||||
Posts labelled 'Go' by Russ Cox, one of the core Go developers.
|
||||
</p>
|
||||
|
||||
<h3 id="blog_iant"><a href="http://www.airs.com/blog/archives/category/programming">Airs</a></h3>
|
||||
<p>
|
||||
Posts labelled 'Programming' by Ian Lance Taylor, one of the core Go developers.
|
||||
</p>
|
||||
|
||||
<h3 id="blog_adg"><a href="http://nf.id.au/tag/go">nf.id.au</a></h3>
|
||||
<p>
|
||||
Posts labelled 'Go' by Andrew Gerrand, one of the core Go developers.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="end-columns"></div>
|
||||
|
||||
125
doc/contrib.html
@@ -1,93 +1,16 @@
|
||||
<!--{
|
||||
"Title": "The Go Project",
|
||||
"Path": "/project/"
|
||||
}-->
|
||||
|
||||
<img class="gopher" src="/doc/gopher/project.png" />
|
||||
|
||||
<div id="manual-nav"></div>
|
||||
|
||||
<p>
|
||||
Go is an open source project developed by a team at
|
||||
<a href="//google.com/">Google</a> and many
|
||||
<a href="/CONTRIBUTORS">contributors</a> from the open source community.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Go is distributed under a <a href="/LICENSE">BSD-style license</a>.
|
||||
</p>
|
||||
|
||||
<h3 id="announce"><a href="//groups.google.com/group/golang-announce">Announcements Mailing List</a></h3>
|
||||
<p>
|
||||
A low traffic mailing list for important announcements, such as new releases.
|
||||
</p>
|
||||
<p>
|
||||
We encourage all Go users to subscribe to
|
||||
<a href="//groups.google.com/group/golang-announce">golang-announce</a>.
|
||||
</p>
|
||||
|
||||
|
||||
<h2 id="go1">Version history</h2>
|
||||
|
||||
<h3 id="release"><a href="/doc/devel/release.html">Release History</a></h3>
|
||||
<p>A summary of the changes between Go releases.</p>
|
||||
|
||||
<h4 id="go1notes"><a href="/doc/go1">Go 1 Release Notes</a></h4>
|
||||
<p>
|
||||
A guide for updating your code to work with Go 1.
|
||||
</p>
|
||||
|
||||
<h4 id="release notes"><a href="/doc/go1.1">Go 1.1 Release Notes</a></h4>
|
||||
<p>
|
||||
A list of significant changes in Go 1.1, with instructions for updating
|
||||
your code where necessary.
|
||||
Each point release includes a similar document appropriate for that
|
||||
release: <a href="/doc/go1.2">Go 1.2</a>, <a href="/doc/go1.3">Go 1.3</a>,
|
||||
and so on.
|
||||
</p>
|
||||
|
||||
<h3 id="go1compat"><a href="/doc/go1compat">Go 1 and the Future of Go Programs</a></h3>
|
||||
<p>
|
||||
What Go 1 defines and the backwards-compatibility guarantees one can expect as
|
||||
Go 1 matures.
|
||||
</p>
|
||||
|
||||
|
||||
<h2 id="resources">Developer Resources</h2>
|
||||
|
||||
<h3 id="source"><a href="https://code.google.com/p/go/source">Source Code</a></h3>
|
||||
<p>Check out the Go source code.</p>
|
||||
|
||||
<h3 id="golang-dev"><a href="https://groups.google.com/group/golang-dev">Developer</a> and
|
||||
<a href="https://groups.google.com/group/golang-codereviews">Code Review Mailing List</a></h3>
|
||||
<p>The <a href="https://groups.google.com/group/golang-dev">golang-dev</a>
|
||||
mailing list is for discussing code changes to the Go project.
|
||||
The <a href="https://groups.google.com/group/golang-codereviews">golang-codereviews</a>
|
||||
mailing list is for actual reviewing of the code changes (CLs).</p>
|
||||
|
||||
<p>For general discussion of Go programming, see <a
|
||||
href="https://groups.google.com/group/golang-nuts">golang-nuts</a>.</p>
|
||||
|
||||
<h3 id="golang-checkins"><a href="https://groups.google.com/group/golang-checkins">Checkins Mailing List</a></h3>
|
||||
<p>A mailing list that receives a message summarizing each checkin to the Go repository.</p>
|
||||
|
||||
<h3 id="golang-bugs"><a href="https://groups.google.com/group/golang-bugs">Bugs Mailing List</a></h3>
|
||||
<p>A mailing list that receives each update to the Go <a href="//golang.org/issue">issue tracker</a>.</p>
|
||||
|
||||
<h3 id="build_status"><a href="//build.golang.org/">Build Status</a></h3>
|
||||
<p>View the status of Go builds across the supported operating
|
||||
systems and architectures.</p>
|
||||
<!-- title Contributing -->
|
||||
|
||||
<div class="left-column">
|
||||
|
||||
<h2 id="howto">How you can help</h2>
|
||||
|
||||
<h3><a href="https://code.google.com/p/go/issues">Reporting issues</a></h3>
|
||||
<h3>Reporting issues</h3>
|
||||
|
||||
<p>
|
||||
If you spot bugs, mistakes, or inconsistencies in the Go project's code or
|
||||
documentation, please let us know by
|
||||
<a href="https://code.google.com/p/go/issues/entry">filing a ticket</a>
|
||||
on our <a href="https://code.google.com/p/go/issues">issue tracker</a>.
|
||||
<a href="http://code.google.com/p/go/issues/entry">filing a ticket</a>
|
||||
on our <a href="http://code.google.com/p/go/issues">issue tracker</a>.
|
||||
(Of course, you should check it's not an existing issue before creating
|
||||
a new one.)
|
||||
</p>
|
||||
@@ -96,18 +19,48 @@ a new one.)
|
||||
We pride ourselves on being meticulous; no issue is too small.
|
||||
</p>
|
||||
|
||||
<h3><a href="/doc/contribute.html">Contributing code</a></h3>
|
||||
<h3>Contributing code</h3>
|
||||
|
||||
<p>
|
||||
Go is an open source project and we welcome contributions from the community.
|
||||
</p>
|
||||
<p>
|
||||
To get started, read these <a href="/doc/contribute.html">contribution
|
||||
To get started, read these <a href="contribute.html">contribution
|
||||
guidelines</a> for information on design, testing, and our code review process.
|
||||
</p>
|
||||
<p>
|
||||
Check <a href="https://code.google.com/p/go/issues">the tracker</a> for
|
||||
Check <a href="http://code.google.com/p/go/issues">the tracker</a> for
|
||||
open issues that interest you. Those labeled
|
||||
<a href="https://code.google.com/p/go/issues/list?q=status=HelpWanted">HelpWanted</a>
|
||||
<a href="http://code.google.com/p/go/issues/list?q=status=HelpWanted">HelpWanted</a>
|
||||
are particularly in need of outside help.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="right-column">
|
||||
|
||||
<h2 id="">The Go Project</h2>
|
||||
|
||||
<h3 id="build_status"><a href="http://godashboard.appspot.com/">Build Status</a></h3>
|
||||
<p>View the status of Go builds across the supported operating
|
||||
systems and architectures.</p>
|
||||
|
||||
<h3 id="roadmap"><a href="devel/roadmap.html">Roadmap</a></h3>
|
||||
<p>Features and ideas being developed or discussed by the Go team.</p>
|
||||
|
||||
<h3 id="release"><a href="devel/release.html">Release History</a></h3>
|
||||
<p>A summary of the changes between tagged releases of Go.</p>
|
||||
|
||||
<h3 id="golang-dev"><a href="http://groups.google.com/group/golang-dev">Developer Mailing List</a></h3>
|
||||
<p>The <a href="http://groups.google.com/group/golang-dev">golang-dev</a>
|
||||
mailing list is for discussing and reviewing code for the Go project.</p>
|
||||
<p>For general discussion of Go programming, see <a
|
||||
href="http://groups.google.com/group/golang-nuts">golang-nuts</a>.</p>
|
||||
|
||||
<h3 id="golang-checkins"><a href="http://groups.google.com/group/golang-checkins">Checkins Mailing List</a></h3>
|
||||
<p>A mailing list that receives a message summarizing each checkin to the Go repository.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="end-columns"></div>
|
||||
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
<!--{
|
||||
"Title": "Contribution Guidelines"
|
||||
}-->
|
||||
<!-- Contribution Guidelines -->
|
||||
|
||||
<h2 id="Introduction">Introduction</h2>
|
||||
|
||||
<p>
|
||||
This document explains how to contribute changes to the Go project.
|
||||
It assumes you have installed Go using the
|
||||
<a href="/doc/install/source">installation instructions</a> and
|
||||
<a href="install.html">installation instructions</a> and
|
||||
have <a href="code.html">written and tested your code</a>.
|
||||
(Note that the <code>gccgo</code> frontend lives elsewhere;
|
||||
see <a href="gccgo_contribute.html">Contributing to gccgo</a>.)
|
||||
@@ -22,7 +20,7 @@ you're working on if you want it to become part of the main repository.
|
||||
|
||||
<p>
|
||||
Before undertaking to write something new for the Go project, send
|
||||
mail to the <a href="https://groups.google.com/group/golang-nuts">mailing
|
||||
mail to the <a href="http://groups.google.com/group/golang-nuts">mailing
|
||||
list</a> to discuss what you plan to do. This gives everyone a
|
||||
chance to validate the design, helps prevent duplication of effort,
|
||||
and ensures that the idea fits inside the goals for the language
|
||||
@@ -45,18 +43,25 @@ tree to make sure the changes don't break other packages or programs:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
$ cd go/src
|
||||
$ ./all.bash
|
||||
cd $GOROOT/src
|
||||
./all.bash
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
(To build under Windows use <code>all.bat</code>.)
|
||||
The final line printed by <code>make all</code> should be of the form:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
<i>N</i> known bugs; 0 unexpected bugs
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
After running for a while, the command should print "<code>ALL TESTS PASSED</code>".
|
||||
The value of <i>N</i> varies over time, but the line must
|
||||
say “<code>0 unexpected bugs</code>” and must not
|
||||
add “<code>test output differs</code>.”
|
||||
</p>
|
||||
|
||||
|
||||
<h2 id="Code_review">Code review</h2>
|
||||
|
||||
<p>
|
||||
@@ -97,72 +102,45 @@ the code review extension disables the standard <code>hg commit</code>
|
||||
command.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Mercurial power users: if you prefer to use the Mercurial Queues extension, see
|
||||
<a href="codereview_with_mq.html">Using Mercurial Queues with Codereview</a>.
|
||||
</p>
|
||||
|
||||
<h3>Configure the extension</h3>
|
||||
|
||||
<p>Edit <code>.hg/hgrc</code> in the root of your Go checkout to add:</p>
|
||||
<p>Edit <code>$GOROOT/.hg/hgrc</code> to add:</p>
|
||||
|
||||
<pre>
|
||||
[extensions]
|
||||
codereview = /path/to/go/lib/codereview/codereview.py
|
||||
codereview = YOUR_GO_ROOT/lib/codereview/codereview.py
|
||||
|
||||
[ui]
|
||||
username = Your Name <you@server.dom>
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
<p>Replace YOUR_GO_ROOT with the value of <code>$GOROOT</code>.
|
||||
The Mercurial configuration file format does not allow environment variable substitution.
|
||||
The <code>username</code> information will not be used unless
|
||||
you are a committer (see below), but Mercurial complains if it is missing.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
As the codereview extension is only enabled for your Go checkout, the remainder of this document assumes you
|
||||
are inside the go directory when issuing commands.
|
||||
</p>
|
||||
|
||||
<p>To contribute to subrepositories, edit the <code>.hg/hgrc</code> for each
|
||||
subrepository in the same way. For example, add the codereview extension to
|
||||
<code>code.google.com/p/go.tools/.hg/hgrc</code>.
|
||||
</p>
|
||||
|
||||
<h3>Understanding the extension</h3>
|
||||
|
||||
<p>After adding the code review extension, you can run</p>
|
||||
|
||||
<pre>
|
||||
$ hg help codereview
|
||||
</pre>
|
||||
|
||||
<p>to learn more about its commands. To learn about a specific code-review-specific
|
||||
command such as <code>change</code>, run</p>
|
||||
|
||||
<pre>
|
||||
$ hg help change
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Windows users may need to perform extra steps to get the code review
|
||||
extension working. See the
|
||||
<a href="https://code.google.com/p/go-wiki/wiki/CodeReview">CodeReview page</a>
|
||||
on the <a href="https://code.google.com/p/go-wiki/wiki">Go Wiki</a> for details.
|
||||
</p>
|
||||
|
||||
<h3>Log in to the code review site.</h3>
|
||||
|
||||
<p>
|
||||
The code review server uses a Google Account to authenticate.
|
||||
(If you can use the account to
|
||||
<a href="https://www.google.com/accounts/Login?hl=en&continue=http://www.google.com/">sign in at google.com</a>,
|
||||
you can use it to sign in to the code review server.)
|
||||
you can use it to sign in to the code review server.
|
||||
The email address you use on the Code Review site
|
||||
will be recorded in the <a href="https://code.google.com/p/go/source/list">Mercurial change log</a>
|
||||
will be recorded in the <a href="http://code.google.com/p/go/source/list">Mercurial change log</a>
|
||||
and in the <a href="/CONTRIBUTORS"><code>CONTRIBUTORS</code></a> file.
|
||||
You can <a href="https://www.google.com/accounts/NewAccount">create a Google Account</a>
|
||||
associated with any address where you receive email.
|
||||
If you've enabled the two-step verification feature, don't forget to generate an
|
||||
application-specific password and use that when prompted for a password.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
$ cd $GOROOT
|
||||
$ hg code-login
|
||||
Email (login for uploading to codereview.appspot.com): rsc@golang.org
|
||||
Password for rsc@golang.org:
|
||||
@@ -172,7 +150,7 @@ Saving authentication cookies to /Users/rsc/.codereview_upload_cookies_coderevie
|
||||
|
||||
<h3>Configure your account settings.</h3>
|
||||
|
||||
<p>Edit your <a href="https://codereview.appspot.com/settings">code review settings</a>.
|
||||
<p>Edit your <a href="http://codereview.appspot.com/settings">code review settings</a>.
|
||||
Grab a nickname.
|
||||
Many people prefer to set the Context option to
|
||||
“Whole file” to see more context when reviewing changes.
|
||||
@@ -183,19 +161,6 @@ can use that nickname as a shorthand for naming reviewers and the CC list.
|
||||
For example, <code>rsc</code> is an alias for <code>rsc@golang.org</code>.
|
||||
</p>
|
||||
|
||||
<h3>Switch to the default branch</h3>
|
||||
|
||||
<p>
|
||||
Most Go installations use a release branch, but new changes should
|
||||
only be made to the default branch. (They may be applied later to a release
|
||||
branch as part of the release process.)
|
||||
Before making a change, make sure you use the default branch:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
$ hg update default
|
||||
</pre>
|
||||
|
||||
<h3>Make a change</h3>
|
||||
|
||||
<p>
|
||||
@@ -234,9 +199,9 @@ Description:
|
||||
<enter description here>
|
||||
|
||||
Files:
|
||||
src/math/sin.go
|
||||
src/math/tan.go
|
||||
src/regexp/regexp.go
|
||||
src/pkg/math/sin.go
|
||||
src/pkg/math/tan.go
|
||||
src/pkg/regexp/regexp.go
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
@@ -244,11 +209,10 @@ The <code>Reviewer</code> line lists the reviewers assigned
|
||||
to this change, and the <code>CC</code> line lists people to
|
||||
notify about the change.
|
||||
These can be code review nicknames or arbitrary email addresses.
|
||||
Unless explicitly told otherwise, such as in the discussion leading
|
||||
up to sending in the change list, leave the reviewer field blank.
|
||||
This means that the
|
||||
<a href="https://groups.google.com/group/golang-codereviews">golang-codereviews@googlegroups.com</a>
|
||||
mailing list will be used as the reviewer.
|
||||
If you don't know who is best to review the change, set the
|
||||
reviewer field to the
|
||||
<a href="http://groups.google.com/group/golang-dev">golang-dev@googlegroups.com</a>
|
||||
mailing list.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
@@ -277,7 +241,7 @@ After editing, the template might now read:
|
||||
# Lines beginning with # are ignored.
|
||||
# Multi-line values should be indented.
|
||||
|
||||
Reviewer: golang-codereviews@googlegroups.com
|
||||
Reviewer: golang-dev@googlegroups.com
|
||||
CC: math-nuts@swtch.com
|
||||
|
||||
Description:
|
||||
@@ -287,17 +251,15 @@ Description:
|
||||
Fixes issue 159.
|
||||
|
||||
Files:
|
||||
src/math/sin.go
|
||||
src/math/tan.go
|
||||
src/pkg/math/sin.go
|
||||
src/pkg/math/tan.go
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The special sentence “Fixes issue 159.” associates
|
||||
the change with issue 159 in the <a href="https://code.google.com/p/go/issues/list">Go issue tracker</a>.
|
||||
the change with issue 159 in the <a href="http://code.google.com/p/go/issues/list">Go issue tracker</a>.
|
||||
When this change is eventually submitted, the issue
|
||||
tracker will automatically mark the issue as fixed.
|
||||
(These conventions are described in detail by the
|
||||
<a href="https://code.google.com/p/support/wiki/IssueTracker#Integration_with_version_control">Google Project Hosting Issue Tracker documentation</a>.)
|
||||
</p>
|
||||
|
||||
<p>
|
||||
@@ -309,124 +271,18 @@ which <code>hg change</code> will print, something like:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
CL created: https://codereview.appspot.com/99999
|
||||
</pre>
|
||||
|
||||
<h3>Mail the change for review</h3>
|
||||
|
||||
<p>
|
||||
Creating or uploading the change uploads a copy of the diff to the code review server,
|
||||
but it does not notify anyone about it. To do that, you need to run <code>hg mail</code>
|
||||
(see below).
|
||||
</p>
|
||||
|
||||
<p>To send out a change for review, run <code>hg mail</code> using the change list number
|
||||
assigned during <code>hg change</code>:</p>
|
||||
|
||||
<pre>
|
||||
$ hg mail 99999
|
||||
</pre>
|
||||
|
||||
<p>You can add to the <code>Reviewer:</code> and <code>CC:</code> lines
|
||||
using the <code>-r</code> or <code>--cc</code> options.
|
||||
In the above example, we could have left the <code>Reviewer</code> and <code>CC</code>
|
||||
lines blank and then run:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
$ hg mail -r golang-codereviews@googlegroups.com --cc math-nuts@swtch.com 99999
|
||||
</pre>
|
||||
|
||||
<p>to achieve the same effect.</p>
|
||||
|
||||
<p>Note that <code>-r</code> and <code>--cc</code> cannot be spelled <code>--r</code> or <code>-cc</code>.</p>
|
||||
|
||||
<p>
|
||||
If your change relates to an open issue, please add a comment to the issue
|
||||
announcing your proposed fix, including a link to your CL.
|
||||
</p>
|
||||
|
||||
<h3>Reviewing code</h3>
|
||||
|
||||
<p>
|
||||
Running <code>hg mail</code> will send an email to you and the reviewers
|
||||
asking them to visit the issue's URL and make comments on the change.
|
||||
When done, the reviewer clicks “Publish and Mail comments”
|
||||
to send comments back.
|
||||
</p>
|
||||
|
||||
|
||||
<h3>Revise and upload</h3>
|
||||
|
||||
<p>
|
||||
When you have revised the code and are ready for another round of review,
|
||||
you can upload your change and send mail asking the reviewers to
|
||||
please take another look (<code>PTAL</code>). Use the change list number
|
||||
assigned during <code>hg change</code>
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
$ hg mail 99999
|
||||
</pre>
|
||||
|
||||
|
||||
<p>
|
||||
Or to upload your change without sending a notification, run
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
$ hg upload 99999
|
||||
CL created: http://codereview.appspot.com/99999
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
You will probably revise your code in response to the reviewer comments.
|
||||
You might also visit the code review web page and reply to the comments,
|
||||
letting the reviewer know that you've addressed them or explain why you
|
||||
haven't. When you're done replying, click “Publish and Mail comments”
|
||||
to send the line-by-line replies and any other comments.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The reviewer can comment on the new copy, and the process repeats.
|
||||
The reviewer approves the change by replying with a mail that says
|
||||
<code>LGTM</code>: looks good to me.
|
||||
If you need to re-edit the change description,
|
||||
run <code>hg change 99999</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
You can see a list of your pending changes by running <code>hg pending</code> (<code>hg p</code> for short).
|
||||
</p>
|
||||
|
||||
<h3>Adding or removing files from an existing change</h3>
|
||||
|
||||
<p>
|
||||
If you need to re-edit the change description, or change the files included in the CL,
|
||||
run <code>hg change 99999</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Alternatively, you can use
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
$ hg file 99999 somefile
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
to add <code>somefile</code> to CL 99999, and
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
$ hg file -d 99999 somefile
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
to remove <code>somefile</code> from the CL.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
A file may only belong to a single active CL at a time. <code>hg file</code>
|
||||
will issue a warning if a file is moved between changes.
|
||||
</p>
|
||||
|
||||
<h3>Synchronize your client</h3>
|
||||
|
||||
@@ -457,11 +313,11 @@ adding changesets
|
||||
adding manifests
|
||||
adding file changes
|
||||
added 1 changeset with 2 changes to 2 files
|
||||
getting src/flag/flag.go
|
||||
getting src/pkg/flag/flag.go
|
||||
couldn't find merge tool hgmerge
|
||||
merging src/flag/flag_test.go
|
||||
merging src/pkg/flag/flag_test.go
|
||||
warning: conflicts during merge.
|
||||
<i>merging src/flag/flag_test.go failed!</i>
|
||||
<i>merging src/pkg/flag/flag_test.go failed!</i>
|
||||
1 file updated, 0 files merged, 0 files removed, 1 file unresolved
|
||||
use 'hg resolve' to retry unresolved file merges
|
||||
$
|
||||
@@ -473,7 +329,7 @@ Mercurial failed to merge your changes with the independent change.
|
||||
When this happens, Mercurial leaves both edits in the file,
|
||||
marked by <code><<<<<<<</code> and
|
||||
<code>>>>>>>></code>.
|
||||
It is now your job to edit the file to combine them.
|
||||
it is now your job to edit the file to combine them.
|
||||
Continuing the example, searching for those strings in <code>flag_test.go</code>
|
||||
might turn up:
|
||||
</p>
|
||||
@@ -517,43 +373,61 @@ changes, but you may still need to run
|
||||
<code>hg resolve -m</code> to mark the conflict resolved.
|
||||
</p>
|
||||
|
||||
<h3>Reviewing code by others</h3>
|
||||
<h3>Mail the change for review</h3>
|
||||
|
||||
<p>
|
||||
You can import a CL proposed by someone else into your local Mercurial client
|
||||
by using the <code>hg clpatch</code> command. Running
|
||||
<p>To send out a change for review, run <code>hg mail</code> using the change list number
|
||||
assigned during <code>hg change</code>:</p>
|
||||
|
||||
<pre>
|
||||
$ hg mail 99999
|
||||
</pre>
|
||||
|
||||
<p>You can add to the <code>Reviewer:</code> and <code>CC:</code> lines
|
||||
using the <code>-r</code> or <code>--cc</code> options.
|
||||
In the above example, we could have left the <code>Reviewer</code> and <code>CC</code>
|
||||
lines blank and then run:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
$ hg clpatch 99999
|
||||
$ hg mail -r golang-dev@googlegroups.com --cc math-nuts@swtch.com 99999
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
will apply the latest diff for CL 99999 to your working copy. If any of the
|
||||
files referenced in CL 99999 have local modifications, <code>clpatch</code>
|
||||
will refuse to apply the whole diff. Once applied, CL 99999 will show up in
|
||||
the output of <code>hg pending</code> and others.
|
||||
</p>
|
||||
<p>to achieve the same effect.</p>
|
||||
|
||||
<p>Note that <code>-r</code> and <code>--cc</code> cannot be spelled <code>--r</code> or <code>-cc</code>.</p>
|
||||
|
||||
|
||||
<h3>Reviewing code</h3>
|
||||
|
||||
<p>
|
||||
To revert a CL you have applied locally, use the <code>hg revert</code>
|
||||
command. Running
|
||||
Running <code>hg mail</code> will send an email to you and the reviewers
|
||||
asking them to visit the issue's URL and make coments on the change.
|
||||
When done, the reviewer clicks “Publish and Mail comments”
|
||||
to send comments back.
|
||||
</p>
|
||||
|
||||
|
||||
<h3>Revise and upload</h3>
|
||||
|
||||
<p>You will probably revise your code in response to the reviewer comments.
|
||||
When you have revised the code and are ready for another round of review, run
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
$ hg revert @99999
|
||||
$ hg mail 99999
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
will revert any files mentioned on CL 99999 to their original state. This can
|
||||
be an effective way of reverting one CL revision and applying another.
|
||||
<p>again to upload the latest copy and send mail asking the reviewers to please take another look
|
||||
(<code>PTAL</code>).
|
||||
You might also visit the code review web page and reply to the comments,
|
||||
letting the reviewer know that you've addressed them or explain why you
|
||||
haven't. When you're done replying, click “Publish and Mail comments”
|
||||
to send the line-by-line replies and any other comments.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Once the CL has been submitted, the next time you run <code>hg sync</code>
|
||||
it will be removed from your local pending list. Occasionally the pending list
|
||||
can get out of sync leaving stale references to closed or abandoned CLs.
|
||||
You can use <code>hg change -D 99999</code> to remove the reference to CL 99999.
|
||||
The reviewer can comment on the new copy, and the process repeats.
|
||||
The reviewer approves the change by replying with a mail that says
|
||||
<code>LGTM</code>: looks good to me.
|
||||
</p>
|
||||
|
||||
<h3>Submit the change after the review</h3>
|
||||
@@ -561,27 +435,6 @@ You can use <code>hg change -D 99999</code> to remove the reference to CL 99999.
|
||||
<p>
|
||||
After the code has been <code>LGTM</code>'ed, it is time to submit
|
||||
it to the Mercurial repository.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If you are not a committer, you cannot submit the change directly.
|
||||
Instead a committer, usually the reviewer who said <code>LGTM</code>,
|
||||
will run:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
$ hg clpatch 99999
|
||||
$ hg submit 99999
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The <code>submit</code> command submits the code. You will be listed as the
|
||||
author, but the change message will also indicate who the committer was.
|
||||
Your local client will notice that the change has been submitted
|
||||
when you next run <code>hg sync</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If you are a committer, you can run:
|
||||
</p>
|
||||
|
||||
@@ -598,7 +451,8 @@ in the repository.
|
||||
|
||||
<p>
|
||||
If your local copy of the repository is out of date,
|
||||
<code>hg submit</code> will refuse the change:
|
||||
<code>hg submit</code>
|
||||
will refuse the change:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
@@ -606,25 +460,41 @@ $ hg submit 99999
|
||||
local repository out of date; must sync before submit
|
||||
</pre>
|
||||
|
||||
<h3>More information</h3>
|
||||
|
||||
<p>
|
||||
In addition to the information here, the Go community maintains a <a href="https://code.google.com/p/go-wiki/wiki/CodeReview">CodeReview</a> wiki page.
|
||||
Feel free to contribute to this page as you learn the review process.
|
||||
If you are not a committer, you cannot submit the change directly.
|
||||
Instead, a committer, usually the reviewer who said <code>LGTM</code>,
|
||||
will run:
|
||||
</p>
|
||||
|
||||
<h2 id="copyright">Copyright</h2>
|
||||
<pre>
|
||||
$ hg clpatch 99999
|
||||
$ hg submit 99999
|
||||
</pre>
|
||||
|
||||
<p>The <code>clpatch</code> command imports your change 99999 into
|
||||
the committer's local Mercurial client, at which point the committer
|
||||
can check or test the code more.
|
||||
(Anyone can run <code>clpatch</code> to try a change that
|
||||
has been uploaded to the code review server.)
|
||||
The <code>submit</code> command submits the code. You will be listed as the
|
||||
author, but the change message will also indicate who the committer was.
|
||||
Your local client will notice that the change has been submitted
|
||||
when you next run <code>hg sync</code>.
|
||||
</p>
|
||||
|
||||
|
||||
<h3 id="copyright">Copyright</h3>
|
||||
|
||||
<p>Files in the Go repository don't list author names,
|
||||
both to avoid clutter and to avoid having to keep the lists up to date.
|
||||
Instead, your name will appear in the <a href="https://code.google.com/p/go/source/list">Mercurial change log</a>
|
||||
Instead, your name will appear in the <a href="http://code.google.com/p/go/source/list">Mercurial change log</a>
|
||||
and in the <a href="/CONTRIBUTORS"><code>CONTRIBUTORS</code></a> file
|
||||
and perhaps the <a href="/AUTHORS"><code>AUTHORS</code></a> file.
|
||||
</p>
|
||||
|
||||
<p>The <a href="/CONTRIBUTORS"><code>CONTRIBUTORS</code></a> file
|
||||
defines who the Go contributors—the people—are;
|
||||
the <a href="/AUTHORS"><code>AUTHORS</code></a> file defines
|
||||
the <a href="/AUTHORS"><code>AUTHORS</code></a> file, which defines
|
||||
who “The Go Authors”—the copyright holders—are.
|
||||
The Go developers at Google will update these files when submitting
|
||||
your first change.
|
||||
@@ -632,15 +502,13 @@ In order for them to do that, you need to have completed one of the
|
||||
contributor license agreements:
|
||||
<ul>
|
||||
<li>
|
||||
If you are the copyright holder, you will need to agree to the
|
||||
<a href="https://developers.google.com/open-source/cla/individual">individual
|
||||
If you are the copyright holder, you will need to agree to
|
||||
the <a href="http://code.google.com/legal/individual-cla-v1.0.html">individual
|
||||
contributor license agreement</a>, which can be completed online.
|
||||
</li>
|
||||
<li>
|
||||
If your organization is the copyright holder, the organization
|
||||
will need to agree to the
|
||||
<a href="https://developers.google.com/open-source/cla/corporate">corporate
|
||||
contributor license agreement</a>.
|
||||
will need to agree to the <a href="http://code.google.com/legal/corporate-cla-v1.0.html">corporate contributor license agreement</a>.
|
||||
(If the copyright holder for your code has already completed the
|
||||
agreement in connection with another Google open source project,
|
||||
it does not need to be completed again.)
|
||||
@@ -654,12 +522,7 @@ This rigmarole needs to be done only for your first submission.
|
||||
<p>Code that you contribute should use the standard copyright header:</p>
|
||||
|
||||
<pre>
|
||||
// Copyright 2014 The Go Authors. All rights reserved.
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Files in the repository are copyright the year they are added. It is not
|
||||
necessary to update the copyright year on files that you change.
|
||||
</p>
|
||||
|
||||
@@ -1,507 +0,0 @@
|
||||
<!--{
|
||||
"Title": "Debugging Go Code with GDB",
|
||||
"Path": "/doc/gdb"
|
||||
}-->
|
||||
|
||||
<p><i>
|
||||
This applies to the <code>gc</code> toolchain. Gccgo has native gdb support.
|
||||
Besides this overview you might want to consult the
|
||||
<a href="http://sourceware.org/gdb/current/onlinedocs/gdb/">GDB manual</a>.
|
||||
</i></p>
|
||||
|
||||
<p>
|
||||
GDB does not understand Go programs well.
|
||||
The stack management, threading, and runtime contain aspects that differ
|
||||
enough from the execution model GDB expects that they can confuse
|
||||
the debugger, even when the program is compiled with gccgo.
|
||||
As a consequence, although GDB can be useful in some situations, it is
|
||||
not a reliable debugger for Go programs, particularly heavily concurrent ones.
|
||||
Moreover, it is not a priority for the Go project to address these issues, which
|
||||
are difficult.
|
||||
In short, the instructions below should be taken only as a guide to how
|
||||
to use GDB when it works, not as a guarantee of success.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
In time, a more Go-centric debugging architecture may be required.
|
||||
</p>
|
||||
|
||||
<h2 id="Introduction">Introduction</h2>
|
||||
|
||||
<p>
|
||||
When you compile and link your Go programs with the <code>gc</code> toolchain
|
||||
on Linux, Mac OS X, FreeBSD or NetBSD, the resulting binaries contain DWARFv3
|
||||
debugging information that recent versions (>7.1) of the GDB debugger can
|
||||
use to inspect a live process or a core dump.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Pass the <code>'-w'</code> flag to the linker to omit the debug information
|
||||
(for example, <code>go build -ldflags "-w" prog.go</code>).
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The code generated by the <code>gc</code> compiler includes inlining of
|
||||
function invocations and registerization of variables. These optimizations
|
||||
can sometimes make debugging with <code>gdb</code> harder. To disable them
|
||||
when debugging, pass the flags <code>-gcflags "-N -l"</code> to the
|
||||
<a href="/cmd/go"><code>go</code></a> command used to build the code being
|
||||
debugged.
|
||||
</p>
|
||||
|
||||
<h3 id="Common_Operations">Common Operations</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
Show file and line number for code, set breakpoints and disassemble:
|
||||
<pre>(gdb) <b>list</b>
|
||||
(gdb) <b>list <i>line</i></b>
|
||||
(gdb) <b>list <i>file.go</i>:<i>line</i></b>
|
||||
(gdb) <b>break <i>line</i></b>
|
||||
(gdb) <b>break <i>file.go</i>:<i>line</i></b>
|
||||
(gdb) <b>disas</b></pre>
|
||||
</li>
|
||||
<li>
|
||||
Show backtraces and unwind stack frames:
|
||||
<pre>(gdb) <b>bt</b>
|
||||
(gdb) <b>frame <i>n</i></b></pre>
|
||||
</li>
|
||||
<li>
|
||||
Show the name, type and location on the stack frame of local variables,
|
||||
arguments and return values:
|
||||
<pre>(gdb) <b>info locals</b>
|
||||
(gdb) <b>info args</b>
|
||||
(gdb) <b>p variable</b>
|
||||
(gdb) <b>whatis variable</b></pre>
|
||||
</li>
|
||||
<li>
|
||||
Show the name, type and location of global variables:
|
||||
<pre>(gdb) <b>info variables <i>regexp</i></b></pre>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h3 id="Go_Extensions">Go Extensions</h3>
|
||||
|
||||
<p>
|
||||
A recent extension mechanism to GDB allows it to load extension scripts for a
|
||||
given binary. The tool chain uses this to extend GDB with a handful of
|
||||
commands to inspect internals of the runtime code (such as goroutines) and to
|
||||
pretty print the built-in map, slice and channel types.
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
Pretty printing a string, slice, map, channel or interface:
|
||||
<pre>(gdb) <b>p <i>var</i></b></pre>
|
||||
</li>
|
||||
<li>
|
||||
A $len() and $cap() function for strings, slices and maps:
|
||||
<pre>(gdb) <b>p $len(<i>var</i>)</b></pre>
|
||||
</li>
|
||||
<li>
|
||||
A function to cast interfaces to their dynamic types:
|
||||
<pre>(gdb) <b>p $dtype(<i>var</i>)</b>
|
||||
(gdb) <b>iface <i>var</i></b></pre>
|
||||
<p class="detail"><b>Known issue:</b> GDB can’t automatically find the dynamic
|
||||
type of an interface value if its long name differs from its short name
|
||||
(annoying when printing stacktraces, the pretty printer falls back to printing
|
||||
the short type name and a pointer).</p>
|
||||
</li>
|
||||
<li>
|
||||
Inspecting goroutines:
|
||||
<pre>(gdb) <b>info goroutines</b>
|
||||
(gdb) <b>goroutine <i>n</i> <i>cmd</i></b>
|
||||
(gdb) <b>help goroutine</b></pre>
|
||||
For example:
|
||||
<pre>(gdb) <b>goroutine 12 bt</b></pre>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
If you'd like to see how this works, or want to extend it, take a look at <a
|
||||
href="/src/runtime/runtime-gdb.py">src/runtime/runtime-gdb.py</a> in
|
||||
the Go source distribution. It depends on some special magic types
|
||||
(<code>hash<T,U></code>) and variables (<code>runtime.m</code> and
|
||||
<code>runtime.g</code>) that the linker
|
||||
(<a href="/src/cmd/ld/dwarf.c">src/cmd/ld/dwarf.c</a>) ensures are described in
|
||||
the DWARF code.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If you're interested in what the debugging information looks like, run
|
||||
'<code>objdump -W 6.out</code>' and browse through the <code>.debug_*</code>
|
||||
sections.
|
||||
</p>
|
||||
|
||||
|
||||
<h3 id="Known_Issues">Known Issues</h3>
|
||||
|
||||
<ol>
|
||||
<li>String pretty printing only triggers for type string, not for types derived
|
||||
from it.</li>
|
||||
<li>Type information is missing for the C parts of the runtime library.</li>
|
||||
<li>GDB does not understand Go’s name qualifications and treats
|
||||
<code>"fmt.Print"</code> as an unstructured literal with a <code>"."</code>
|
||||
that needs to be quoted. It objects even more strongly to method names of
|
||||
the form <code>pkg.(*MyType).Meth</code>.
|
||||
<li>All global variables are lumped into package <code>"main"</code>.</li>
|
||||
</ol>
|
||||
|
||||
<h2 id="Tutorial">Tutorial</h2>
|
||||
|
||||
<p>
|
||||
In this tutorial we will inspect the binary of the
|
||||
<a href="/pkg/regexp/">regexp</a> package's unit tests. To build the binary,
|
||||
change to <code>$GOROOT/src/regexp</code> and run <code>go test -c</code>.
|
||||
This should produce an executable file named <code>regexp.test</code>.
|
||||
</p>
|
||||
|
||||
|
||||
<h3 id="Getting_Started">Getting Started</h3>
|
||||
|
||||
<p>
|
||||
Launch GDB, debugging <code>regexp.test</code>:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
$ <b>gdb regexp.test</b>
|
||||
GNU gdb (GDB) 7.2-gg8
|
||||
Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
License GPLv 3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
|
||||
Type "show copying" and "show warranty" for licensing/warranty details.
|
||||
This GDB was configured as "x86_64-linux".
|
||||
|
||||
Reading symbols from /home/user/go/src/regexp/regexp.test...
|
||||
done.
|
||||
Loading Go Runtime support.
|
||||
(gdb)
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The message <code>"Loading Go Runtime support"</code> means that GDB loaded the
|
||||
extension from <code>$GOROOT/src/runtime/runtime-gdb.py</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
To help GDB find the Go runtime sources and the accompanying support script,
|
||||
pass your <code>$GOROOT</code> with the <code>'-d'</code> flag:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
$ <b>gdb regexp.test -d $GOROOT</b>
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
If for some reason GDB still can't find that directory or that script, you can load
|
||||
it by hand by telling gdb (assuming you have the go sources in
|
||||
<code>~/go/</code>):
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
(gdb) <b>source ~/go/src/runtime/runtime-gdb.py</b>
|
||||
Loading Go Runtime support.
|
||||
</pre>
|
||||
|
||||
<h3 id="Inspecting_the_source">Inspecting the source</h3>
|
||||
|
||||
<p>
|
||||
Use the <code>"l"</code> or <code>"list"</code> command to inspect source code.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
(gdb) <b>l</b>
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
List a specific part of the source parametrizing <code>"list"</code> with a
|
||||
function name (it must be qualified with its package name).
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
(gdb) <b>l main.main</b>
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
List a specific file and line number:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
(gdb) <b>l regexp.go:1</b>
|
||||
(gdb) <i># Hit enter to repeat last command. Here, this lists next 10 lines.</i>
|
||||
</pre>
|
||||
|
||||
|
||||
<h3 id="Naming">Naming</h3>
|
||||
|
||||
<p>
|
||||
Variable and function names must be qualified with the name of the packages
|
||||
they belong to. The <code>Compile</code> function from the <code>regexp</code>
|
||||
package is known to GDB as <code>'regexp.Compile'</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Methods must be qualified with the name of their receiver types. For example,
|
||||
the <code>*Regexp</code> type’s <code>String</code> method is known as
|
||||
<code>'regexp.(*Regexp).String'</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Variables that shadow other variables are magically suffixed with a number in the debug info.
|
||||
Variables referenced by closures will appear as pointers magically prefixed with '&'.
|
||||
</p>
|
||||
|
||||
<h3 id="Setting_breakpoints">Setting breakpoints</h3>
|
||||
|
||||
<p>
|
||||
Set a breakpoint at the <code>TestFind</code> function:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
(gdb) <b>b 'regexp.TestFind'</b>
|
||||
Breakpoint 1 at 0x424908: file /home/user/go/src/regexp/find_test.go, line 148.
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Run the program:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
(gdb) <b>run</b>
|
||||
Starting program: /home/user/go/src/regexp/regexp.test
|
||||
|
||||
Breakpoint 1, regexp.TestFind (t=0xf8404a89c0) at /home/user/go/src/regexp/find_test.go:148
|
||||
148 func TestFind(t *testing.T) {
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Execution has paused at the breakpoint.
|
||||
See which goroutines are running, and what they're doing:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
(gdb) <b>info goroutines</b>
|
||||
1 waiting runtime.gosched
|
||||
* 13 running runtime.goexit
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
the one marked with the <code>*</code> is the current goroutine.
|
||||
</p>
|
||||
|
||||
<h3 id="Inspecting_the_stack">Inspecting the stack</h3>
|
||||
|
||||
<p>
|
||||
Look at the stack trace for where we’ve paused the program:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
(gdb) <b>bt</b> <i># backtrace</i>
|
||||
#0 regexp.TestFind (t=0xf8404a89c0) at /home/user/go/src/regexp/find_test.go:148
|
||||
#1 0x000000000042f60b in testing.tRunner (t=0xf8404a89c0, test=0x573720) at /home/user/go/src/testing/testing.go:156
|
||||
#2 0x000000000040df64 in runtime.initdone () at /home/user/go/src/runtime/proc.c:242
|
||||
#3 0x000000f8404a89c0 in ?? ()
|
||||
#4 0x0000000000573720 in ?? ()
|
||||
#5 0x0000000000000000 in ?? ()
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The other goroutine, number 1, is stuck in <code>runtime.gosched</code>, blocked on a channel receive:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
(gdb) <b>goroutine 1 bt</b>
|
||||
#0 0x000000000040facb in runtime.gosched () at /home/user/go/src/runtime/proc.c:873
|
||||
#1 0x00000000004031c9 in runtime.chanrecv (c=void, ep=void, selected=void, received=void)
|
||||
at /home/user/go/src/runtime/chan.c:342
|
||||
#2 0x0000000000403299 in runtime.chanrecv1 (t=void, c=void) at/home/user/go/src/runtime/chan.c:423
|
||||
#3 0x000000000043075b in testing.RunTests (matchString={void (struct string, struct string, bool *, error *)}
|
||||
0x7ffff7f9ef60, tests= []testing.InternalTest = {...}) at /home/user/go/src/testing/testing.go:201
|
||||
#4 0x00000000004302b1 in testing.Main (matchString={void (struct string, struct string, bool *, error *)}
|
||||
0x7ffff7f9ef80, tests= []testing.InternalTest = {...}, benchmarks= []testing.InternalBenchmark = {...})
|
||||
at /home/user/go/src/testing/testing.go:168
|
||||
#5 0x0000000000400dc1 in main.main () at /home/user/go/src/regexp/_testmain.go:98
|
||||
#6 0x00000000004022e7 in runtime.mainstart () at /home/user/go/src/runtime/amd64/asm.s:78
|
||||
#7 0x000000000040ea6f in runtime.initdone () at /home/user/go/src/runtime/proc.c:243
|
||||
#8 0x0000000000000000 in ?? ()
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The stack frame shows we’re currently executing the <code>regexp.TestFind</code> function, as expected.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
(gdb) <b>info frame</b>
|
||||
Stack level 0, frame at 0x7ffff7f9ff88:
|
||||
rip = 0x425530 in regexp.TestFind (/home/user/go/src/regexp/find_test.go:148);
|
||||
saved rip 0x430233
|
||||
called by frame at 0x7ffff7f9ffa8
|
||||
source language minimal.
|
||||
Arglist at 0x7ffff7f9ff78, args: t=0xf840688b60
|
||||
Locals at 0x7ffff7f9ff78, Previous frame's sp is 0x7ffff7f9ff88
|
||||
Saved registers:
|
||||
rip at 0x7ffff7f9ff80
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The command <code>info locals</code> lists all variables local to the function and their values, but is a bit
|
||||
dangerous to use, since it will also try to print uninitialized variables. Uninitialized slices may cause gdb to try
|
||||
to print arbitrary large arrays.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The function’s arguments:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
(gdb) <b>info args</b>
|
||||
t = 0xf840688b60
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
When printing the argument, notice that it’s a pointer to a
|
||||
<code>Regexp</code> value. Note that GDB has incorrectly put the <code>*</code>
|
||||
on the right-hand side of the type name and made up a 'struct' keyword, in traditional C style.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
(gdb) <b>p re</b>
|
||||
(gdb) p t
|
||||
$1 = (struct testing.T *) 0xf840688b60
|
||||
(gdb) p t
|
||||
$1 = (struct testing.T *) 0xf840688b60
|
||||
(gdb) p *t
|
||||
$2 = {errors = "", failed = false, ch = 0xf8406f5690}
|
||||
(gdb) p *t->ch
|
||||
$3 = struct hchan<*testing.T>
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
That <code>struct hchan<*testing.T></code> is the runtime-internal representation of a channel. It is currently empty, or gdb would have pretty-printed it's contents.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Stepping forward:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
(gdb) <b>n</b> <i># execute next line</i>
|
||||
149 for _, test := range findTests {
|
||||
(gdb) <i># enter is repeat</i>
|
||||
150 re := MustCompile(test.pat)
|
||||
(gdb) <b>p test.pat</b>
|
||||
$4 = ""
|
||||
(gdb) <b>p re</b>
|
||||
$5 = (struct regexp.Regexp *) 0xf84068d070
|
||||
(gdb) <b>p *re</b>
|
||||
$6 = {expr = "", prog = 0xf840688b80, prefix = "", prefixBytes = []uint8, prefixComplete = true,
|
||||
prefixRune = 0, cond = 0 '\000', numSubexp = 0, longest = false, mu = {state = 0, sema = 0},
|
||||
machine = []*regexp.machine}
|
||||
(gdb) <b>p *re->prog</b>
|
||||
$7 = {Inst = []regexp/syntax.Inst = {{Op = 5 '\005', Out = 0, Arg = 0, Rune = []int}, {Op =
|
||||
6 '\006', Out = 2, Arg = 0, Rune = []int}, {Op = 4 '\004', Out = 0, Arg = 0, Rune = []int}},
|
||||
Start = 1, NumCap = 2}
|
||||
</pre>
|
||||
|
||||
|
||||
<p>
|
||||
We can step into the <code>String</code>function call with <code>"s"</code>:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
(gdb) <b>s</b>
|
||||
regexp.(*Regexp).String (re=0xf84068d070, noname=void) at /home/user/go/src/regexp/regexp.go:97
|
||||
97 func (re *Regexp) String() string {
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Get a stack trace to see where we are:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
(gdb) <b>bt</b>
|
||||
#0 regexp.(*Regexp).String (re=0xf84068d070, noname=void)
|
||||
at /home/user/go/src/regexp/regexp.go:97
|
||||
#1 0x0000000000425615 in regexp.TestFind (t=0xf840688b60)
|
||||
at /home/user/go/src/regexp/find_test.go:151
|
||||
#2 0x0000000000430233 in testing.tRunner (t=0xf840688b60, test=0x5747b8)
|
||||
at /home/user/go/src/testing/testing.go:156
|
||||
#3 0x000000000040ea6f in runtime.initdone () at /home/user/go/src/runtime/proc.c:243
|
||||
....
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Look at the source code:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
(gdb) <b>l</b>
|
||||
92 mu sync.Mutex
|
||||
93 machine []*machine
|
||||
94 }
|
||||
95
|
||||
96 // String returns the source text used to compile the regular expression.
|
||||
97 func (re *Regexp) String() string {
|
||||
98 return re.expr
|
||||
99 }
|
||||
100
|
||||
101 // Compile parses a regular expression and returns, if successful,
|
||||
</pre>
|
||||
|
||||
<h3 id="Pretty_Printing">Pretty Printing</h3>
|
||||
|
||||
<p>
|
||||
GDB's pretty printing mechanism is triggered by regexp matches on type names. An example for slices:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
(gdb) <b>p utf</b>
|
||||
$22 = []uint8 = {0 '\000', 0 '\000', 0 '\000', 0 '\000'}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Since slices, arrays and strings are not C pointers, GDB can't interpret the subscripting operation for you, but
|
||||
you can look inside the runtime representation to do that (tab completion helps here):
|
||||
</p>
|
||||
<pre>
|
||||
|
||||
(gdb) <b>p slc</b>
|
||||
$11 = []int = {0, 0}
|
||||
(gdb) <b>p slc-></b><i><TAB></i>
|
||||
array slc len
|
||||
(gdb) <b>p slc->array</b>
|
||||
$12 = (int *) 0xf84057af00
|
||||
(gdb) <b>p slc->array[1]</b>
|
||||
$13 = 0</pre>
|
||||
|
||||
|
||||
|
||||
<p>
|
||||
The extension functions $len and $cap work on strings, arrays and slices:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
(gdb) <b>p $len(utf)</b>
|
||||
$23 = 4
|
||||
(gdb) <b>p $cap(utf)</b>
|
||||
$24 = 4
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Channels and maps are 'reference' types, which gdb shows as pointers to C++-like types <code>hash<int,string>*</code>. Dereferencing will trigger prettyprinting
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Interfaces are represented in the runtime as a pointer to a type descriptor and a pointer to a value. The Go GDB runtime extension decodes this and automatically triggers pretty printing for the runtime type. The extension function <code>$dtype</code> decodes the dynamic type for you (examples are taken from a breakpoint at <code>regexp.go</code> line 293.)
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
(gdb) <b>p i</b>
|
||||
$4 = {str = "cbb"}
|
||||
(gdb) <b>whatis i</b>
|
||||
type = regexp.input
|
||||
(gdb) <b>p $dtype(i)</b>
|
||||
$26 = (struct regexp.inputBytes *) 0xf8400b4930
|
||||
(gdb) <b>iface i</b>
|
||||
regexp.input: struct regexp.inputBytes *
|
||||
</pre>
|
||||
11
doc/devel/index.html
Normal file
@@ -0,0 +1,11 @@
|
||||
<!-- The Go project -->
|
||||
|
||||
<ul>
|
||||
<li><a href="roadmap.html">Roadmap</a></li>
|
||||
<li><a href="release.html">Release history</a></li>
|
||||
<li><a href="weekly.html">Weekly snapshot history</a></li>
|
||||
<li><a href="http://godashboard.appspot.com">Build and benchmark status</a></li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li><a href="../contribute.html">Contributing code</a></li>
|
||||
</ul>
|
||||
@@ -1,420 +1,19 @@
|
||||
<!--{
|
||||
"Title": "Release History"
|
||||
}-->
|
||||
<!-- Release History -->
|
||||
|
||||
<p>This page summarizes the changes between official stable releases of Go.
|
||||
The <a href="//code.google.com/p/go/source/list">Mercurial change log</a>
|
||||
has the full details.</p>
|
||||
Between releases we issue less stable
|
||||
<a href="http://blog.golang.org/2011/03/go-becomes-more-stable.html">weekly snapshots</a>.
|
||||
The <a href="weekly.html">weekly snapshot history</a> contains more detail,
|
||||
and the <a href="http://code.google.com/p/go/source/list">Mercurial change log</a>
|
||||
has full details.</p>
|
||||
|
||||
<p>To update to a specific release, use:</p>
|
||||
|
||||
<pre>
|
||||
hg pull
|
||||
hg update <i>tag</i>
|
||||
hg update release.r<i>NN</i>
|
||||
</pre>
|
||||
|
||||
<h2 id="go1.3">go1.3 (released 2014/06/18)</h2>
|
||||
|
||||
<p>
|
||||
Go 1.3 is a major release of Go.
|
||||
Read the <a href="/doc/go1.3">Go 1.3 Release Notes</a> for more information.
|
||||
</p>
|
||||
|
||||
<h3 id="go1.3.minor">Minor revisions</h3>
|
||||
|
||||
<p>
|
||||
go1.3.1 (released 2014/08/13) includes bug fixes to the compiler and the <code>runtime</code>, <code>net</code>, and <code>crypto/rsa</code> packages.
|
||||
See the <a href="//code.google.com/p/go/source/list?name=release-branch.go1.3&r=073fc578434bf3e1e22749b559d273c8da728ebb">change history</a> for details.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
go1.3.2 (released 2014/09/25) includes bug fixes to cgo and the crypto/tls packages.
|
||||
See the <a href="//code.google.com/p/go/source/list?name=release-branch.go1.3&r=go1.3.2">change history</a> for details.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
go1.3.3 (released 2014/09/30) includes further bug fixes to cgo, the runtime package, and the nacl port.
|
||||
See the <a href="//code.google.com/p/go/source/list?name=release-branch.go1.3&r=go1.3.3">change history</a> for details.
|
||||
</p>
|
||||
|
||||
<h2 id="go1.2">go1.2 (released 2013/12/01)</h2>
|
||||
|
||||
<p>
|
||||
Go 1.2 is a major release of Go.
|
||||
Read the <a href="/doc/go1.2">Go 1.2 Release Notes</a> for more information.
|
||||
</p>
|
||||
|
||||
<h3 id="go1.2.minor">Minor revisions</h3>
|
||||
|
||||
<p>
|
||||
go1.2.1 (released 2014/03/02) includes bug fixes to the <code>runtime</code>, <code>net</code>, and <code>database/sql</code> packages.
|
||||
See the <a href="//code.google.com/p/go/source/list?name=release-branch.go1.2&r=7ada9e760ce34e78aee5b476c9621556d0fa5d31">change history</a> for details.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
go1.2.2 (released 2014/05/05) includes a
|
||||
<a href="//code.google.com/p/go/source/detail?r=bda3619e7a2c&repo=tools">security fix</a>
|
||||
that affects the tour binary included in the binary distributions (thanks to Guillaume T).
|
||||
</p>
|
||||
|
||||
<h2 id="go1.1">go1.1 (released 2013/05/13)</h2>
|
||||
|
||||
<p>
|
||||
Go 1.1 is a major release of Go.
|
||||
Read the <a href="/doc/go1.1">Go 1.1 Release Notes</a> for more information.
|
||||
</p>
|
||||
|
||||
<h3 id="go1.1.minor">Minor revisions</h3>
|
||||
|
||||
<p>
|
||||
go1.1.1 (released 2013/06/13) includes several compiler and runtime bug fixes.
|
||||
See the <a href="//code.google.com/p/go/source/list?name=release-branch.go1.1&r=43c4a41d24382a56a90e924800c681e435d9e399">change history</a> for details.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
go1.1.2 (released 2013/08/13) includes fixes to the <code>gc</code> compiler
|
||||
and <code>cgo</code>, and the <code>bufio</code>, <code>runtime</code>,
|
||||
<code>syscall</code>, and <code>time</code> packages.
|
||||
See the <a href="//code.google.com/p/go/source/list?name=release-branch.go1.1&r=a6a9792f94acd4ff686b2bc57383d163608b91cf">change history</a> for details.
|
||||
If you use package syscall's <code>Getrlimit</code> and <code>Setrlimit</code>
|
||||
functions under Linux on the ARM or 386 architectures, please note change
|
||||
<a href="//golang.org/change/55ac276af5a7">55ac276af5a7</a>
|
||||
that fixes <a href="//golang.org/issue/5949">issue 5949</a>.
|
||||
</p>
|
||||
|
||||
<h2 id="go1">go1 (released 2012/03/28)</h2>
|
||||
|
||||
<p>
|
||||
Go 1 is a major release of Go that will be stable in the long term.
|
||||
Read the <a href="/doc/go1.html">Go 1 Release Notes</a> for more information.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
It is intended that programs written for Go 1 will continue to compile and run
|
||||
correctly, unchanged, under future versions of Go 1.
|
||||
Read the <a href="/doc/go1compat.html">Go 1 compatibility document</a> for more
|
||||
about the future of Go 1.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The go1 release corresponds to
|
||||
<code><a href="weekly.html#2012-03-27">weekly.2012-03-27</a></code>.
|
||||
</p>
|
||||
|
||||
<h3 id="go1.minor">Minor revisions</h3>
|
||||
|
||||
<p>
|
||||
go1.0.1 (released 2012/04/25) was issued to
|
||||
<a href="//golang.org/change/a890477d3dfb">fix</a> an
|
||||
<a href="//golang.org/issue/3545">escape analysis bug</a>
|
||||
that can lead to memory corruption.
|
||||
It also includes several minor code and documentation fixes.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
go1.0.2 (released 2012/06/13) was issued to fix two bugs in the implementation
|
||||
of maps using struct or array keys:
|
||||
<a href="//golang.org/issue/3695">issue 3695</a> and
|
||||
<a href="//golang.org/issue/3573">issue 3573</a>.
|
||||
It also includes many minor code and documentation fixes.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
go1.0.3 (released 2012/09/21) includes minor code and documentation fixes.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
See the <a href="//code.google.com/p/go/source/list?name=release-branch.go1">go1 release branch history</a> for the complete list of changes.
|
||||
</p>
|
||||
|
||||
<h2 id="r60">r60 (released 2011/09/07)</h2>
|
||||
|
||||
<p>
|
||||
The r60 release corresponds to
|
||||
<code><a href="weekly.html#2011-08-17">weekly.2011-08-17</a></code>.
|
||||
This section highlights the most significant changes in this release.
|
||||
For a more detailed summary, see the
|
||||
<a href="weekly.html#2011-08-17">weekly release notes</a>.
|
||||
For complete information, see the
|
||||
<a href="//code.google.com/p/go/source/list?r=release-branch.r60">Mercurial change list</a>.
|
||||
</p>
|
||||
|
||||
<h3 id="r60.lang">Language</h3>
|
||||
|
||||
<p>
|
||||
An "else" block is now required to have braces except if the body of the "else"
|
||||
is another "if". Since gofmt always puts those braces in anyway,
|
||||
gofmt-formatted programs will not be affected.
|
||||
To fix other programs, run gofmt.
|
||||
</p>
|
||||
|
||||
<h3 id="r60.pkg">Packages</h3>
|
||||
|
||||
<p>
|
||||
<a href="/pkg/http/">Package http</a>'s URL parsing and query escaping code
|
||||
(such as <code>ParseURL</code> and <code>URLEscape</code>) has been moved to
|
||||
the new <a href="/pkg/url/">url package</a>, with several simplifications to
|
||||
the names. Client code can be updated automatically with gofix.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<a href="/pkg/image/">Package image</a> has had significant changes made to the
|
||||
<code>Pix</code> field of struct types such as
|
||||
<a href="/pkg/image/#RGBA">image.RGBA</a> and
|
||||
<a href="/pkg/image/#NRGBA">image.NRGBA</a>.
|
||||
The <a href="/pkg/image/#Image">image.Image</a> interface type has not changed,
|
||||
though, and you should not need to change your code if you don't explicitly
|
||||
refer to <code>Pix</code> fields. For example, if you decode a number of images
|
||||
using the <a href="/pkg/image/jpeg/">image/jpeg</a> package, compose them using
|
||||
<a href="/pkg/image/draw/">image/draw</a>, and then encode the result using
|
||||
<a href="/pkg/img/png">image/png</a>, then your code should still work as
|
||||
before.
|
||||
If your code <i>does</i> refer to <code>Pix</code> fields see the
|
||||
<a href="/doc/devel/weekly.html#2011-07-19">weekly.2011-07-19</a>
|
||||
snapshot notes for how to update your code.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<a href="/pkg/template/">Package template</a> has been replaced with a new
|
||||
templating package (formerly <code>exp/template</code>). The original template
|
||||
package is still available as <a href="/pkg/old/template/">old/template</a>.
|
||||
The <code>old/template</code> package is deprecated and will be removed.
|
||||
The Go tree has been updated to use the new template package. We encourage
|
||||
users of the old template package to switch to the new one. Code that uses
|
||||
<code>template</code> or <code>exp/template</code> will need to change its
|
||||
import lines to <code>"old/template"</code> or <code>"template"</code>,
|
||||
respectively.
|
||||
</p>
|
||||
|
||||
<h3 id="r60.cmd">Tools</h3>
|
||||
|
||||
<p>
|
||||
<a href="/cmd/goinstall/">Goinstall</a> now uses a new tag selection scheme.
|
||||
When downloading or updating, goinstall looks for a tag or branch with the
|
||||
<code>"go."</code> prefix that corresponds to the local Go version. For Go
|
||||
<code>release.r58</code> it looks for <code>go.r58</code>. For
|
||||
<code>weekly.2011-06-03</code> it looks for <code>go.weekly.2011-06-03</code>.
|
||||
If the specific <code>go.X</code> tag or branch is not found, it chooses the
|
||||
closest earlier version. If an appropriate tag or branch is found, goinstall
|
||||
uses that version of the code. Otherwise it uses the default version selected
|
||||
by the version control system. Library authors are encouraged to use the
|
||||
appropriate tag or branch names in their repositories to make their libraries
|
||||
more accessible.
|
||||
</p>
|
||||
|
||||
<h3 id="r60.minor">Minor revisions</h3>
|
||||
|
||||
<p>
|
||||
r60.1 includes a
|
||||
<a href="//golang.org/change/1824581bf62d">linker
|
||||
fix</a>, a pair of
|
||||
<a href="//golang.org/change/9ef4429c2c64">goplay</a>
|
||||
<a href="//golang.org/change/d42ed8c3098e">fixes</a>,
|
||||
and a <code>json</code> package
|
||||
<a href="//golang.org/change/d5e97874fe84">fix</a> and
|
||||
a new
|
||||
<a href="//golang.org/change/4f0e6269213f">struct tag
|
||||
option</a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
r60.2
|
||||
<a href="//golang.org/change/ff19536042ac">fixes</a>
|
||||
a memory leak involving maps.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
r60.3 fixes a
|
||||
<a href="//golang.org/change/01fa62f5e4e5">reflect bug</a>.
|
||||
</p>
|
||||
|
||||
<h2 id="r59">r59 (released 2011/08/01)</h2>
|
||||
|
||||
<p>
|
||||
The r59 release corresponds to
|
||||
<code><a href="weekly.html#2011-07-07">weekly.2011-07-07</a></code>.
|
||||
This section highlights the most significant changes in this release.
|
||||
For a more detailed summary, see the
|
||||
<a href="weekly.html#2011-07-07">weekly release notes</a>.
|
||||
For complete information, see the
|
||||
<a href="//code.google.com/p/go/source/list?r=release-branch.r59">Mercurial change list</a>.
|
||||
</p>
|
||||
|
||||
<h3 id="r59.lang">Language</h3>
|
||||
|
||||
<p>
|
||||
This release includes a language change that restricts the use of
|
||||
<code>goto</code>. In essence, a <code>goto</code> statement outside a block
|
||||
cannot jump to a label inside that block. Your code may require changes if it
|
||||
uses <code>goto</code>.
|
||||
See <a href="//golang.org/change/dc6d3cf9279d">this
|
||||
changeset</a> for how the new rule affected the Go tree.
|
||||
</p>
|
||||
|
||||
<h3 id="r59.pkg">Packages</h3>
|
||||
|
||||
<p>
|
||||
As usual, <a href="/cmd/gofix/">gofix</a> will handle the bulk of the rewrites
|
||||
necessary for these changes to package APIs.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<a href="/pkg/http">Package http</a> has a new
|
||||
<a href="/pkg/http/#FileSystem">FileSystem</a> interface that provides access
|
||||
to files. The <a href="/pkg/http/#FileServer">FileServer</a> helper now takes a
|
||||
<code>FileSystem</code> argument instead of an explicit file system root. By
|
||||
implementing your own <code>FileSystem</code> you can use the
|
||||
<code>FileServer</code> to serve arbitrary data.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<a href="/pkg/os/">Package os</a>'s <code>ErrorString</code> type has been
|
||||
hidden. Most uses of <code>os.ErrorString</code> can be replaced with
|
||||
<a href="/pkg/os/#NewError">os.NewError</a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<a href="/pkg/reflect/">Package reflect</a> supports a new struct tag scheme
|
||||
that enables sharing of struct tags between multiple packages.
|
||||
In this scheme, the tags must be of the form:
|
||||
</p>
|
||||
<pre>
|
||||
`key:"value" key2:"value2"`
|
||||
</pre>
|
||||
<p>
|
||||
The <a href="/pkg/reflect/#StructField">StructField</a> type's Tag field now
|
||||
has type <a href="/pkg/reflect/#StructTag">StructTag</a>, which has a
|
||||
<code>Get</code> method. Clients of <a href="/pkg/json">json</a> and
|
||||
<a href="/pkg/xml">xml</a> will need to be updated. Code that says
|
||||
</p>
|
||||
<pre>
|
||||
type T struct {
|
||||
X int "name"
|
||||
}
|
||||
</pre>
|
||||
<p>
|
||||
should become
|
||||
</p>
|
||||
<pre>
|
||||
type T struct {
|
||||
X int `json:"name"` // or `xml:"name"`
|
||||
}
|
||||
</pre>
|
||||
<p>
|
||||
Use <a href="/cmd/govet/">govet</a> to identify struct tags that need to be
|
||||
changed to use the new syntax.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<a href="/pkg/sort/">Package sort</a>'s <code>IntArray</code> type has been
|
||||
renamed to <a href="/pkg/sort/#IntSlice">IntSlice</a>, and similarly for
|
||||
<a href="/pkg/sort/#Float64Slice">Float64Slice</a> and
|
||||
<a href="/pkg/sort/#StringSlice">StringSlice</a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<a href="/pkg/strings/">Package strings</a>'s <code>Split</code> function has
|
||||
itself been split into <a href="/pkg/strings/#Split">Split</a> and
|
||||
<a href="/pkg/strings/#SplitN">SplitN</a>.
|
||||
<code>SplitN</code> is the same as the old <code>Split</code>.
|
||||
The new <code>Split</code> is equivalent to <code>SplitN</code> with a final
|
||||
argument of -1.
|
||||
</p>
|
||||
|
||||
<a href="/pkg/image/draw/">Package image/draw</a>'s
|
||||
<a href="/pkg/image/draw/#Draw">Draw</a> function now takes an additional
|
||||
argument, a compositing operator.
|
||||
If in doubt, use <a href="/pkg/image/draw/#Op">draw.Over</a>.
|
||||
</p>
|
||||
|
||||
<h3 id="r59.cmd">Tools</h3>
|
||||
|
||||
<p>
|
||||
<a href="/cmd/goinstall/">Goinstall</a> now installs packages and commands from
|
||||
arbitrary remote repositories (not just Google Code, Github, and so on).
|
||||
See the <a href="/cmd/goinstall/">goinstall documentation</a> for details.
|
||||
</p>
|
||||
|
||||
<h2 id="r58">r58 (released 2011/06/29)</h2>
|
||||
|
||||
<p>
|
||||
The r58 release corresponds to
|
||||
<code><a href="weekly.html#2011-06-09">weekly.2011-06-09</a></code>
|
||||
with additional bug fixes.
|
||||
This section highlights the most significant changes in this release.
|
||||
For a more detailed summary, see the
|
||||
<a href="weekly.html#2011-06-09">weekly release notes</a>.
|
||||
For complete information, see the
|
||||
<a href="//code.google.com/p/go/source/list?r=release-branch.r58">Mercurial change list</a>.
|
||||
</p>
|
||||
|
||||
<h3 id="r58.lang">Language</h3>
|
||||
|
||||
<p>
|
||||
This release fixes a <a href="//golang.org/change/b720749486e1">use of uninitialized memory in programs that misuse <code>goto</code></a>.
|
||||
</p>
|
||||
|
||||
<h3 id="r58.pkg">Packages</h3>
|
||||
|
||||
<p>
|
||||
As usual, <a href="/cmd/gofix/">gofix</a> will handle the bulk of the rewrites
|
||||
necessary for these changes to package APIs.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<a href="/pkg/http/">Package http</a> drops the <code>finalURL</code> return
|
||||
value from the <a href="/pkg/http/#Client.Get">Client.Get</a> method. The value
|
||||
is now available via the new <code>Request</code> field on <a
|
||||
href="/pkg/http/#Response">http.Response</a>.
|
||||
Most instances of the type map[string][]string in have been
|
||||
replaced with the new <a href="/pkg/http/#Values">Values</a> type.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<a href="/pkg/exec/">Package exec</a> has been redesigned with a more
|
||||
convenient and succinct API.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<a href="/pkg/strconv/">Package strconv</a>'s <a href="/pkg/strconv/#Quote">Quote</a>
|
||||
function now escapes only those Unicode code points not classified as printable
|
||||
by <a href="/pkg/unicode/#IsPrint">unicode.IsPrint</a>.
|
||||
Previously Quote would escape all non-ASCII characters.
|
||||
This also affects the <a href="/pkg/fmt/">fmt</a> package's <code>"%q"</code>
|
||||
formatting directive. The previous quoting behavior is still available via
|
||||
strconv's new <a href="/pkg/strconv/#QuoteToASCII">QuoteToASCII</a> function.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<a href="/pkg/os/signal/">Package os/signal</a>'s
|
||||
<a href="/pkg/os/#Signal">Signal</a> and
|
||||
<a href="/pkg/os/#UnixSignal">UnixSignal</a> types have been moved to the
|
||||
<a href="/pkg/os/">os</a> package.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<a href="/pkg/image/draw/">Package image/draw</a> is the new name for
|
||||
<code>exp/draw</code>. The GUI-related code from <code>exp/draw</code> is now
|
||||
located in the <a href="/pkg/exp/gui/">exp/gui</a> package.
|
||||
</p>
|
||||
|
||||
<h3 id="r58.cmd">Tools</h3>
|
||||
|
||||
<p>
|
||||
<a href="/cmd/goinstall/">Goinstall</a> now observes the GOPATH environment
|
||||
variable to build and install your own code and external libraries outside of
|
||||
the Go tree (and avoid writing Makefiles).
|
||||
</p>
|
||||
|
||||
|
||||
<h3 id="r58.minor">Minor revisions</h3>
|
||||
|
||||
<p>r58.1 adds
|
||||
<a href="//golang.org/change/293c25943586">build</a> and
|
||||
<a href="//golang.org/change/bf17e96b6582">runtime</a>
|
||||
changes to make Go run on OS X 10.7 Lion.
|
||||
</p>
|
||||
|
||||
<h2 id="r57">r57 (released 2011/05/03)</h2>
|
||||
|
||||
<p>
|
||||
@@ -425,7 +24,7 @@ This section highlights the most significant changes in this release.
|
||||
For a more detailed summary, see the
|
||||
<a href="weekly.html#2011-04-27">weekly release notes</a>.
|
||||
For complete information, see the
|
||||
<a href="//code.google.com/p/go/source/list?r=release-branch.r57">Mercurial change list</a>.
|
||||
<a href="http://code.google.com/p/go/source/list?r=release-branch.r57">Mercurial change list</a>.
|
||||
</p>
|
||||
|
||||
<p>The new <a href="/cmd/gofix">gofix</a> tool finds Go programs that use old APIs and rewrites them to use
|
||||
@@ -436,7 +35,7 @@ future changes to the libraries.
|
||||
Gofix can’t
|
||||
handle all situations perfectly, so read and test the changes it makes before
|
||||
committing them.
|
||||
See <a href="//blog.golang.org/2011/04/introducing-gofix.html">the gofix blog post</a> for more
|
||||
See <a href="http://blog.golang.org/2011/04/introducing-gofix.html">the gofix blog post</a> for more
|
||||
information.</p>
|
||||
|
||||
<h3 id="r57.lang">Language</h3>
|
||||
@@ -482,7 +81,7 @@ For clients, there are new
|
||||
<a href="/pkg/http/#Client">Client</a> and <a href="/pkg/http/#Transport">Transport</a>
|
||||
abstractions that give more control over HTTP details such as headers sent
|
||||
and redirections followed. These abstractions make it easy to implement
|
||||
custom clients that add functionality such as <a href="//code.google.com/p/goauth2/source/browse/oauth/oauth.go">OAuth2</a>.
|
||||
custom clients that add functionality such as <a href="http://code.google.com/p/goauth2/source/browse/oauth/oauth.go">OAuth2</a>.
|
||||
For servers, <a href="/pkg/http/#ResponseWriter">ResponseWriter</a>
|
||||
has dropped its non-essential methods.
|
||||
The Hijack and Flush methods are no longer required;
|
||||
@@ -526,7 +125,7 @@ implements all the possible value methods.
|
||||
Instead of a type switch on a Value <code>v</code>, switch on <code>v.Kind()</code>.
|
||||
Typeof and NewValue are now called <a href="/pkg/reflect/#Type.TypeOf">TypeOf</a> and <a href="/pkg/reflect/#Value.ValueOf">ValueOf</a>
|
||||
To create a writable Value, use <code>New(t).Elem()</code> instead of <code>Zero(t)</code>.
|
||||
See <a href="//golang.org/change/843855f3c026">the change description</a>
|
||||
See <a href="http://code.google.com/p/go/source/detail?r=843855f3c026">the change description</a>
|
||||
for the full details.
|
||||
The new API allows a more efficient implementation of Value
|
||||
that avoids many of the allocations required by the previous API.
|
||||
@@ -537,7 +136,7 @@ Remember that gofix will handle the bulk of the rewrites
|
||||
necessary for these changes to package APIs.
|
||||
</p>
|
||||
|
||||
<h3 id="r57.cmd">Tools</h3>
|
||||
<h3 id="r57.tool">Tools</h3>
|
||||
|
||||
<p><a href="/cmd/gofix/">Gofix</a>, a new command, is described above.</p>
|
||||
|
||||
@@ -562,8 +161,7 @@ For other uses, see the <a href="/pkg/runtime/pprof/">runtime/pprof</a> document
|
||||
|
||||
<h3 id="r57.minor">Minor revisions</h3>
|
||||
|
||||
<p>r57.1 fixes a <a href="//golang.org/change/ff2bc62726e7145eb2ecc1e0f076998e4a8f86f0">nil pointer dereference in http.FormFile</a>.</p>
|
||||
<p>r57.2 fixes a <a href="//golang.org/change/063b0ff67d8277df03c956208abc068076818dae">use of uninitialized memory in programs that misuse <code>goto</code></a>.</p>
|
||||
<p>r57.1 fixes a <a href="http://code.google.com/p/go/source/detail?r=ff2bc62726e7145eb2ecc1e0f076998e4a8f86f0">nil pointer dereference in http.FormFile</a>.</p>
|
||||
|
||||
<h2 id="r56">r56 (released 2011/03/16)</h2>
|
||||
|
||||
|
||||
135
doc/devel/roadmap.html
Normal file
@@ -0,0 +1,135 @@
|
||||
<!-- Roadmap -->
|
||||
|
||||
<h2 id="Roadmap">Go Roadmap</h2>
|
||||
|
||||
<p>
|
||||
This page lists features and ideas being developed or discussed by the
|
||||
Go team. This list will be updated as work continues.
|
||||
|
||||
<p>
|
||||
The roadmap should be discussed on
|
||||
the <a href="http://groups.google.com/group/golang-nuts">golang-nuts
|
||||
mailing list</a>.
|
||||
|
||||
<h3 id="Language_roadmap">
|
||||
Language roadmap</h3>
|
||||
|
||||
<p>
|
||||
This is a list of language changes that are being considered.
|
||||
Appearance on this list is no guarantee that the change will be
|
||||
accepted.
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
Possibly rewrite restriction on goto across variable declarations.
|
||||
<li>
|
||||
Variant types. A way to define a type as being the union of some set
|
||||
of types.
|
||||
<li>
|
||||
Generics. An active topic of discussion.
|
||||
<li>
|
||||
Methods for operators, to allow a type to use arithmetic notation for
|
||||
expressions.
|
||||
<li>
|
||||
Possibly allow top-level packages to be given names other than main.
|
||||
</ul>
|
||||
|
||||
<h3 id="Implementation_roadmap">
|
||||
Implementation roadmap</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
Improved garbage collector.
|
||||
<li>
|
||||
Debugger.
|
||||
<li>
|
||||
App Engine support.
|
||||
<li>
|
||||
Improved implementation documentation.
|
||||
</ul>
|
||||
|
||||
<h4 id="Gc_roadmap">
|
||||
Gc compiler roadmap</h4>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
Implement goto restrictions.
|
||||
<li>
|
||||
Improved optimization.
|
||||
<li>
|
||||
Use escape analysis to keep more data on stack.
|
||||
</ul>
|
||||
|
||||
<h4 id="Gccgo_roadmap">
|
||||
Gccgo compiler roadmap</h4>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
Implement goto restrictions.
|
||||
<li>
|
||||
Use goroutines rather than threads.
|
||||
<li>
|
||||
Separate gcc interface from frontend proper.
|
||||
<li>
|
||||
Use escape analysis to keep more data on stack.
|
||||
</ul>
|
||||
|
||||
<h4 id="Tools_roadmap">
|
||||
Tools roadmap</h4>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
Strengthen goinstall until it can displace make for most builds.
|
||||
</ul>
|
||||
|
||||
<h4 id="Packages_roadmap">
|
||||
Packages roadmap</h4>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
Faster, RE2-like regular expressions.
|
||||
<li>
|
||||
Comprehensive support for international text.
|
||||
<li>
|
||||
Support for international dates, times, etc.
|
||||
<li>
|
||||
Support for multilingual messages.
|
||||
</ul>
|
||||
|
||||
|
||||
<h3 id="done">Done</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
gc: Generate DWARF debug info.
|
||||
<li>
|
||||
gc: Provide gdb support for runtime facilities.
|
||||
<li>
|
||||
Safe compilation mode: generate code that is guaranteed not to obtain an invalid memory address other than via <code>import "unsafe"</code>.
|
||||
<li>
|
||||
Gccgo: garbage collection.
|
||||
<li>
|
||||
SWIG support.
|
||||
<li>
|
||||
Simpler semicolon rules.
|
||||
<li>
|
||||
A more general definition of <code>...</code> in parameter lists.
|
||||
<li>
|
||||
Explicit conversions from <code>string</code>
|
||||
to <code>[]byte</code> and <code>[]int</code>.
|
||||
<li>
|
||||
A function that will be run by the garbage collector when an item is freed
|
||||
(runtime.SetFinalizer).
|
||||
<li>
|
||||
Public continuous build and benchmark infrastructure (gobuilder).
|
||||
<li>
|
||||
Package manager (goinstall).
|
||||
<li>
|
||||
A means of recovering from a panic (recover).
|
||||
<li>
|
||||
5g: Better floating point support.
|
||||
<li>
|
||||
Improved CGO including some mechanism for calling back from C to Go.
|
||||
<li>
|
||||
Faster, allocation-light reflection.
|
||||
</ul>
|
||||
274
doc/docs.html
@@ -1,199 +1,195 @@
|
||||
<!--{
|
||||
"Title": "Documentation",
|
||||
"Path": "/doc/"
|
||||
}-->
|
||||
|
||||
<p>
|
||||
The Go programming language is an open source project to make programmers more
|
||||
productive.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Go is expressive, concise, clean, and efficient. Its concurrency
|
||||
mechanisms make it easy to write programs that get the most out of multicore
|
||||
and networked machines, while its novel type system enables flexible and
|
||||
modular program construction. Go compiles quickly to machine code yet has the
|
||||
convenience of garbage collection and the power of run-time reflection. It's a
|
||||
fast, statically typed, compiled language that feels like a dynamically typed,
|
||||
interpreted language.
|
||||
</p>
|
||||
|
||||
<div id="manual-nav"></div>
|
||||
|
||||
<h2>Installing Go</h2>
|
||||
|
||||
<h3><a href="/doc/install">Getting Started</a></h3>
|
||||
<p>
|
||||
Instructions for downloading and installing the Go compilers, tools, and
|
||||
libraries.
|
||||
</p>
|
||||
<!-- title Documentation -->
|
||||
|
||||
<div class="left-column">
|
||||
|
||||
<h2 id="learning">Learning Go</h2>
|
||||
|
||||
<img class="gopher" src="/doc/gopher/doc.png"/>
|
||||
|
||||
<h3 id="go_tour"><a href="//tour.golang.org/">A Tour of Go</a></h3>
|
||||
<p>
|
||||
An interactive introduction to Go in three sections.
|
||||
The first section covers basic syntax and data structures; the second discusses
|
||||
methods and interfaces; and the third introduces Go's concurrency primitives.
|
||||
Each section concludes with a few exercises so you can practice what you've
|
||||
learned. You can <a href="//tour.golang.org/">take the tour online</a> or
|
||||
<a href="//code.google.com/p/go-tour/">install it locally</a>.
|
||||
If you're new to Go, we recommend you work through the
|
||||
<a href="go_tutorial.html">tutorial</a>. The
|
||||
<a href="go_spec.html">language specification</a> has all the details should
|
||||
you want to explore.
|
||||
</p>
|
||||
<p>
|
||||
Once you've learned a little about the language,
|
||||
<a href="effective_go.html">Effective Go</a> will help you learn the style and
|
||||
idioms of programming in Go.
|
||||
</p>
|
||||
|
||||
<h3 id="code"><a href="code.html">How to write Go code</a></h3>
|
||||
<h3 id="orig_tutorial"><a href="go_tutorial.html">A Tutorial for the Go Programming Language</a></h3>
|
||||
<p>
|
||||
Also available as a
|
||||
<a href="//www.youtube.com/watch?v=XCsL89YtqCs">screencast</a>, this doc
|
||||
explains how to use the <a href="/cmd/go/">go command</a> to fetch, build, and
|
||||
install packages, commands, and run tests.
|
||||
The first tutorial. An introductory text that touches upon several core
|
||||
concepts: syntax, types, allocation, constants, I/O, sorting, printing,
|
||||
goroutines, and channels.
|
||||
</p>
|
||||
|
||||
<h3 id="effective_go"><a href="effective_go.html">Effective Go</a></h3>
|
||||
<p>
|
||||
A document that gives tips for writing clear, idiomatic Go code.
|
||||
A must read for any new Go programmer. It augments the tour and
|
||||
A must read for any new Go programmer. It augments the tutorial and
|
||||
the language specification, both of which should be read first.
|
||||
</p>
|
||||
|
||||
<h3 id="faq"><a href="/doc/faq">Frequently Asked Questions (FAQ)</a></h3>
|
||||
<h3 id="go_faq"><a href="go_faq.html">Frequently Asked Questions (FAQ)</a></h3>
|
||||
<p>
|
||||
Answers to common questions about Go.
|
||||
</p>
|
||||
|
||||
<h3 id="wiki"><a href="/wiki">The Go Wiki</a></h3>
|
||||
<p>A wiki maintained by the Go community.</p>
|
||||
|
||||
<h4 id="learn_more">More</h4>
|
||||
<h3 id="code"><a href="code.html">How to write Go code</a></h3>
|
||||
<p>
|
||||
See the <a href="/wiki/Learn">Learn</a> page at the <a href="/wiki">Wiki</a>
|
||||
for more Go learning resources.
|
||||
How to write a new package and how to test code.
|
||||
</p>
|
||||
|
||||
<h3 id="codelab_wiki"><a href="codelab/wiki/">Codelab: Writing Web Applications</a></h3>
|
||||
<p>
|
||||
This codelab takes the reader through the creation of a simple wiki web
|
||||
application. It touches on structs, methods, file I/O, http, regular expressions,
|
||||
and closures.
|
||||
</p>
|
||||
|
||||
<h2 id="references">References</h2>
|
||||
<h3 id="codewalks"><a href="codewalk/">Codewalks</a></h3>
|
||||
<p>
|
||||
Guided tours of Go programs.
|
||||
</p>
|
||||
|
||||
<h3 id="go_for_cpp_programmers"><a href="go_for_cpp_programmers.html">Go for C++ Programmers</a></h3>
|
||||
<p>
|
||||
An introduction to Go for C++ programmers.
|
||||
</p>
|
||||
|
||||
<h2 id="tutorials_nonenglish">Non-English Documentation</h2>
|
||||
|
||||
<h3 id="docs_cn">Chinese — 中文</h3>
|
||||
|
||||
<ul>
|
||||
<li><a href="http://code.google.com/p/golang-china/">golang-china</a> - a broad range of Go documentation.</li>
|
||||
<li><a href="http://code.google.com/p/ac-me/downloads/detail?name=fango.pdf">Effective Go and Tutorial</a></li>
|
||||
</ul>
|
||||
|
||||
<h3 id="docs_de">German — Deutsch</h3>
|
||||
|
||||
<ul>
|
||||
<li><a href="http://bitloeffel.de/DOC/golang/go_tutorial_de.html">Eine Anleitung zum Programmieren in Go</a> - the Go Tutorial.</li>
|
||||
<li><a href="http://bitloeffel.de/DOC/golang/effective_go_de.html">Wirkungsvoll Go programmieren</a> - Effective Go.</li>
|
||||
<li><a href="http://bitloeffel.de/DOC/golang/code_de.html">Wie man Go-Kode schreibt</a> - How to Write Go Code.</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="docs_jp">Japanese — 日本語</h3>
|
||||
<ul>
|
||||
<li><a href="http://golang.jp/">golang.jp</a> - Go documentation and news.
|
||||
</ul>
|
||||
|
||||
<h3 id="docs_ru">Russian — Русский</h3>
|
||||
<ul>
|
||||
<li><a href="http://golanguage.ru/">golanguage.ru</a> - Go documentation.
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class="right-column">
|
||||
|
||||
<h2 id="References">References</h2>
|
||||
|
||||
<p>Keep these under your pillow.</p>
|
||||
|
||||
<h3 id="pkg"><a href="/pkg/">Package Documentation</a></h3>
|
||||
<p>
|
||||
The documentation for the Go standard library.
|
||||
The built-in documentation for the Go standard library.
|
||||
</p>
|
||||
|
||||
<h3 id="cmd"><a href="/doc/cmd">Command Documentation</a></h3>
|
||||
<h3 id="cmd"><a href="/cmd/">Command Documentation</a></h3>
|
||||
<p>
|
||||
The documentation for the Go tools.
|
||||
The built-in documentation for the Go tools.
|
||||
</p>
|
||||
|
||||
<h3 id="spec"><a href="/ref/spec">Language Specification</a></h3>
|
||||
<h3 id="spec"><a href="go_spec.html">Language Specification</a></h3>
|
||||
<p>
|
||||
The official Go Language specification.
|
||||
The official Go Language specification.
|
||||
</p>
|
||||
|
||||
<h3 id="go_mem"><a href="/ref/mem">The Go Memory Model</a></h3>
|
||||
<h3 id="go_mem"><a href="go_mem.html">The Go Memory Model</a></h3>
|
||||
<p>
|
||||
A document that specifies the conditions under which reads of a variable in
|
||||
one goroutine can be guaranteed to observe values produced by writes to the
|
||||
same variable in a different goroutine.
|
||||
</p>
|
||||
|
||||
<h3 id="release"><a href="/doc/devel/release.html">Release History</a></h3>
|
||||
<p>A summary of the changes between Go releases.</p>
|
||||
<h2 id="videos_talks">Videos and Talks</h2>
|
||||
|
||||
|
||||
<h2 id="articles">Articles</h2>
|
||||
|
||||
<h3 id="blog"><a href="//blog.golang.org/">The Go Blog</a></h3>
|
||||
<p>The official blog of the Go project, featuring news and in-depth articles by
|
||||
the Go team and guests.</p>
|
||||
|
||||
<h4>Codewalks</h4>
|
||||
<h3 id="go_programming"><a href="http://www.youtube.com/watch?v=jgVhBThJdXc">Go Programming</a></h3>
|
||||
<p>
|
||||
Guided tours of Go programs.
|
||||
A presentation delivered by Rob Pike and Russ Cox at Google I/O 2010. It
|
||||
illustrates how programming in Go differs from other languages through a set of
|
||||
examples demonstrating features particular to Go. These include concurrency,
|
||||
embedded types, methods on any type, and program construction using interfaces.
|
||||
</p>
|
||||
|
||||
<h3 id="practical_go_programming"><a href="http://osdc.blip.tv/file/4432146/">Practical Go Programming</a></h3>
|
||||
<p>
|
||||
This talk presents the development of a complete web application in Go.
|
||||
It looks at design, storage, concurrency, and scaling issues in detail, using
|
||||
the simple example of an URL shortening service.
|
||||
See the <a href="http://wh3rd.net/practical-go/">presentation slides</a>.
|
||||
</p>
|
||||
|
||||
<h3 id="techtalk"><a href="http://www.youtube.com/watch?v=rKnDgT73v8s">The Go Tech Talk</a></h3>
|
||||
<p>
|
||||
An hour-long talk delivered by Rob Pike at Google in October 2009.
|
||||
The language's first public introduction. (See the <a href="talks/go_talk-20091030.pdf">slides in PDF format</a>.) The language has changed since it was made,
|
||||
but it's still a good introduction.
|
||||
</p>
|
||||
|
||||
<h3 id="gocoding_channel"><a href="http://www.youtube.com/gocoding">gocoding YouTube Channel</a></h3>
|
||||
<p>
|
||||
A YouTube channel that includes screencasts and other Go-related videos:
|
||||
</p>
|
||||
<ul>
|
||||
<li><a href="/doc/codewalk/functions">First-Class Functions in Go</a></li>
|
||||
<li><a href="/doc/codewalk/markov">Generating arbitrary text: a Markov chain algorithm</a></li>
|
||||
<li><a href="/doc/codewalk/sharemem">Share Memory by Communicating</a></li>
|
||||
<li><a href="/doc/articles/wiki/">Writing Web Applications</a> - building a simple web application.</li>
|
||||
<li><a href="http://www.youtube.com/gocoding#p/u/0/jDWBJOXs_iI">Screencast: Writing Go Packages</a> - writing, building, and distributing Go packages.</li>
|
||||
<li><a href="http://www.youtube.com/watch?v=3brH0zOqm0w">Screencast: Testing Go Packages</a> - writing unit tests and benchmarking Go packages.</li>
|
||||
</ul>
|
||||
|
||||
<h4>Language</h4>
|
||||
<ul>
|
||||
<li><a href="/blog/json-rpc-tale-of-interfaces">JSON-RPC: a tale of interfaces</a></li>
|
||||
<li><a href="/blog/gos-declaration-syntax">Go's Declaration Syntax</a></li>
|
||||
<li><a href="/blog/defer-panic-and-recover">Defer, Panic, and Recover</a></li>
|
||||
<li><a href="/blog/go-concurrency-patterns-timing-out-and">Go Concurrency Patterns: Timing out, moving on</a></li>
|
||||
<li><a href="/blog/go-slices-usage-and-internals">Go Slices: usage and internals</a></li>
|
||||
<li><a href="/blog/gif-decoder-exercise-in-go-interfaces">A GIF decoder: an exercise in Go interfaces</a></li>
|
||||
<li><a href="/blog/error-handling-and-go">Error Handling and Go</a></li>
|
||||
<li><a href="/blog/organizing-go-code">Organizing Go code</a></li>
|
||||
</ul>
|
||||
|
||||
<h4>Packages</h4>
|
||||
<ul>
|
||||
<li><a href="/blog/json-and-go">JSON and Go</a> - using the <a href="/pkg/encoding/json/">json</a> package.</li>
|
||||
<li><a href="/blog/gobs-of-data">Gobs of data</a> - the design and use of the <a href="/pkg/encoding/gob/">gob</a> package.</li>
|
||||
<li><a href="/blog/laws-of-reflection">The Laws of Reflection</a> - the fundamentals of the <a href="/pkg/reflect/">reflect</a> package.</li>
|
||||
<li><a href="/blog/go-image-package">The Go image package</a> - the fundamentals of the <a href="/pkg/image/">image</a> package.</li>
|
||||
<li><a href="/blog/go-imagedraw-package">The Go image/draw package</a> - the fundamentals of the <a href="/pkg/image/draw/">image/draw</a> package.</li>
|
||||
</ul>
|
||||
|
||||
<h4>Tools</h4>
|
||||
<ul>
|
||||
<li><a href="/doc/articles/go_command.html">About the Go command</a> - why we wrote it, what it is, what it's not, and how to use it.</li>
|
||||
<li><a href="/blog/c-go-cgo">C? Go? Cgo!</a> - linking against C code with <a href="/cmd/cgo/">cgo</a>.</li>
|
||||
<li><a href="/doc/gdb">Debugging Go Code with GDB</a></li>
|
||||
<li><a href="/blog/godoc-documenting-go-code">Godoc: documenting Go code</a> - writing good documentation for <a href="/cmd/godoc/">godoc</a>.</li>
|
||||
<li><a href="/blog/profiling-go-programs">Profiling Go Programs</a></li>
|
||||
<li><a href="/doc/articles/race_detector.html">Data Race Detector</a> - a manual for the data race detector.</li>
|
||||
<li><a href="/blog/race-detector">Introducing the Go Race Detector</a> - an introduction to the race detector.</li>
|
||||
<li><a href="/doc/asm">A Quick Guide to Go's Assembler</a> - an introduction to the assembler used by Go.</li>
|
||||
</ul>
|
||||
|
||||
<h4 id="articles_more">More</h4>
|
||||
<h3 id="jaoo_go"><a href="/doc/ExpressivenessOfGo.pdf">The Expressiveness Of Go</a></h3>
|
||||
<p>
|
||||
See the <a href="/wiki/Articles">Articles page</a> at the
|
||||
<a href="/wiki">Wiki</a> for more Go articles.
|
||||
A discussion of the qualities that make Go an expressive and comprehensible
|
||||
language. The talk was presented by Rob Pike at JAOO 2010.
|
||||
The recording of the event was lost due to a hardware error.
|
||||
</p>
|
||||
|
||||
|
||||
<h2 id="talks">Talks</h2>
|
||||
|
||||
<img class="gopher" src="/doc/gopher/talks.png"/>
|
||||
|
||||
<h3 id="video_tour_of_go"><a href="http://research.swtch.com/gotour">A Video Tour of Go</a></h3>
|
||||
<h3 id="oscon_go"><a href="http://www.oscon.com/oscon2010/public/schedule/detail/14760">Another Go at Language Design</a></h3>
|
||||
<p>
|
||||
Three things that make Go fast, fun, and productive:
|
||||
interfaces, reflection, and concurrency. Builds a toy web crawler to
|
||||
demonstrate these.
|
||||
A tour, with some background, of the major features of Go, intended for
|
||||
an audience new to the language. The talk was presented at OSCON 2010.
|
||||
See the <a href="http://assets.en.oreilly.com/1/event/45/Another%20Go%20at%20Language%20Design%20Presentation.pdf">presentation slides</a>.
|
||||
</p>
|
||||
<p>
|
||||
This talk was also delivered at Sydney University in September 2010. A video
|
||||
of the lecture is available
|
||||
<a href="http://sydney.edu.au/engineering/it/videos/seminar_pike">here</a>.
|
||||
</p>
|
||||
|
||||
<h3 id="go_code_that_grows"><a href="//vimeo.com/53221560">Code that grows with grace</a></h3>
|
||||
<h3 id="emerging_go"><a href="http://www.oscon.com/oscon2010/public/schedule/detail/15464">Go Emerging Languages Conference Talk</a></h3>
|
||||
<p>
|
||||
One of Go's key design goals is code adaptability; that it should be easy to take a simple design and build upon it in a clean and natural way. In this talk Andrew Gerrand describes a simple "chat roulette" server that matches pairs of incoming TCP connections, and then use Go's concurrency mechanisms, interfaces, and standard library to extend it with a web interface and other features. While the function of the program changes dramatically, Go's flexibility preserves the original design as it grows.
|
||||
Rob Pike's Emerging Languages Conference presentation delivered in July 2010. See the <a href="http://assets.en.oreilly.com/1/event/45/Go%20Presentation.pdf">presentation slides</a>. Abstract:
|
||||
</p>
|
||||
<p><i>
|
||||
Go’s approach to concurrency differs from that of many languages, even those
|
||||
(such as Erlang) that make concurrency central, yet it has deep roots. The path
|
||||
from Hoare’s 1978 paper to Go provides insight into how and why Go works as it
|
||||
does.
|
||||
</i></p>
|
||||
|
||||
<h3 id="emerging_go"><a href="talks/gofrontend-gcc-summit-2010.pdf">The Go frontend for GCC</a></h3>
|
||||
<p>
|
||||
A description of the Go language frontend for gcc.
|
||||
Ian Lance Taylor's paper delivered at the GCC Summit 2010.
|
||||
</p>
|
||||
|
||||
<h3 id="go_concurrency_patterns"><a href="//www.youtube.com/watch?v=f6kdp27TYZs">Go Concurrency Patterns</a></h3>
|
||||
<h3 id="promo_video"><a href="http://www.youtube.com/watch?v=wwoWei-GAPo">The Go Promo Video</a></h3>
|
||||
<p>
|
||||
Concurrency is the key to designing high performance network services. Go's concurrency primitives (goroutines and channels) provide a simple and efficient means of expressing concurrent execution. In this talk we see how tricky concurrency problems can be solved gracefully with simple Go code.
|
||||
A short promotional video featuring Russ Cox demonstrating Go's fast compiler.
|
||||
</p>
|
||||
|
||||
<h3 id="advanced_go_concurrency_patterns"><a href="//www.youtube.com/watch?v=QDDwwePbDtw">Advanced Go Concurrency Patterns</a></h3>
|
||||
<p>
|
||||
This talk expands on the <i>Go Concurrency Patterns</i> talk to dive deeper into Go's concurrency primitives.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<h4 id="talks_more">More</h4>
|
||||
<p>
|
||||
See the <a href="/talks">Go Talks site</a> and <a href="/wiki/GoTalks">wiki page</a> for more Go talks.
|
||||
</p>
|
||||
|
||||
|
||||
<h2 id="nonenglish">Non-English Documentation</h2>
|
||||
|
||||
<p>
|
||||
See the <a href="/wiki/NonEnglish">NonEnglish</a> page
|
||||
at the <a href="/wiki">Wiki</a> for localized
|
||||
documentation.
|
||||
</p>
|
||||
<div class="end-columns"></div>
|
||||
|
||||
140
doc/frontpage.css
Normal file
@@ -0,0 +1,140 @@
|
||||
/* Overloads to all.css */
|
||||
#container { width: 76em }
|
||||
.left-column { width: 48%; }
|
||||
.right-column { width: 48%; }
|
||||
|
||||
/* Frontpage styles */
|
||||
#content-introductory code {
|
||||
font-family: "Bitstream Vera Sans Mono", "Andale Mono", monospace;
|
||||
}
|
||||
#content-introductory input, select, textarea {
|
||||
font-family: "Bitstream Vera Sans", Verdana, sans-serif;
|
||||
font-size: 1em;
|
||||
}
|
||||
span.keyword {
|
||||
font-family: Cambria, Georgia, Times, "Times New Roman", serif;
|
||||
font-size: 1.15em;
|
||||
font-style: italic;
|
||||
}
|
||||
#content h3, #content h2 {
|
||||
margin: 0;
|
||||
font-size: 1em;
|
||||
background: none;
|
||||
border: none;
|
||||
padding: 0;
|
||||
}
|
||||
#content .more {
|
||||
color: #999;
|
||||
font-weight: normal;
|
||||
}
|
||||
#frontpage h2#branding-tagline {
|
||||
font-weight: normal;
|
||||
font-style: italic;
|
||||
}
|
||||
#resources {
|
||||
position: relative;
|
||||
margin-top: 1em;
|
||||
}
|
||||
#resources h3 {
|
||||
margin-top: 0;
|
||||
margin-bottom: -.5em;
|
||||
font-size: 1em;
|
||||
font-weight: normal;
|
||||
}
|
||||
#resources-users {
|
||||
float: left;
|
||||
width: 48%;
|
||||
}
|
||||
#resources-contributors {
|
||||
float: right;
|
||||
width: 50%;
|
||||
}
|
||||
#resources ul {
|
||||
padding-left: 2em;
|
||||
}
|
||||
#resources li {
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
#content-rotating {
|
||||
height: 200px;
|
||||
}
|
||||
#content-videos {
|
||||
float: left;
|
||||
width: 170px;
|
||||
}
|
||||
#content-videos .thumbnail {
|
||||
width: 150px;
|
||||
height: 103px;
|
||||
background-repeat: no-repeat;
|
||||
border: none;
|
||||
}
|
||||
#content-videos .thumbnail._001 {
|
||||
background: url(/doc/video-001.png);
|
||||
}
|
||||
#content-videos .thumbnail._002 {
|
||||
background: url(/doc/video-002.png);
|
||||
}
|
||||
#content-videos .thumbnail._003 {
|
||||
background: url(/doc/video-003.png);
|
||||
}
|
||||
#content-videos .thumbnail._004 {
|
||||
background: url(/doc/video-004.png);
|
||||
}
|
||||
#content-videos a.video {
|
||||
display: inline-block;
|
||||
width: 150px;
|
||||
margin-right: .30em;
|
||||
margin-top: 1.2em;
|
||||
}
|
||||
#content-videos a.video .caption {
|
||||
display: block;
|
||||
text-align: center;
|
||||
}
|
||||
#content-videos a.video .caption.title {
|
||||
margin-top: .31em;
|
||||
font-weight: bold;
|
||||
}
|
||||
#content-blog ul {
|
||||
margin-top: 1em;
|
||||
margin-left: 0;
|
||||
padding-left: 0;
|
||||
}
|
||||
#content-blog li {
|
||||
list-style: none;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
#content-blog li a {
|
||||
color: #999;
|
||||
text-decoration: none;
|
||||
}
|
||||
#content-blog .date {
|
||||
color: #999;
|
||||
font-size: 0.8em;
|
||||
display: inline-block;
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
#content-blog li a:link .title {
|
||||
color: #04a;
|
||||
}
|
||||
#content-blog li a:visited .title {
|
||||
color: #04a;
|
||||
}
|
||||
#content-blog li a:hover .title {
|
||||
color: #a40;
|
||||
text-decoration: underline;
|
||||
}
|
||||
#content-blog li a:active .title {
|
||||
color: #c00;
|
||||
}
|
||||
.navtop {
|
||||
display: none !important;
|
||||
}
|
||||
.how {
|
||||
float: right;
|
||||
font-size: 75%;
|
||||
}
|
||||
.unsupported {
|
||||
font-weight: bold;
|
||||
color: red;
|
||||
}
|
||||
|
||||
@@ -1,112 +1,99 @@
|
||||
<!--{
|
||||
"Title": "Contributing to the gccgo frontend"
|
||||
}-->
|
||||
<!-- Contributing to the gccgo frontend -->
|
||||
|
||||
<h2>Introduction</h2>
|
||||
|
||||
<p>
|
||||
These are some notes on contributing to the gccgo frontend for GCC.
|
||||
For information on contributing to parts of Go other than gccgo,
|
||||
see <a href="/doc/contribute.html">Contributing to the Go project</a>. For
|
||||
information on building gccgo for yourself,
|
||||
see <a href="/doc/gccgo_install.html">Setting up and using gccgo</a>.
|
||||
For more of the gritty details on the process of doing development
|
||||
with the gccgo frontend,
|
||||
see <a href="https://code.google.com/p/gofrontend/source/browse/HACKING">the
|
||||
file HACKING</a> in the gofrontend repository.
|
||||
These are some notes on contributing to the <code>gccgo</code>
|
||||
frontend for GCC. For information on contributing to parts of Go other
|
||||
than <code>gccgo</code>, see <a href="contribute.html">Contributing to
|
||||
the Go project</a>. For information on building <code>gccgo</code>
|
||||
for yourself, see <a href="gccgo_install.html">Setting up and using
|
||||
gccgo</a>.
|
||||
</p>
|
||||
|
||||
<h2>Legal Prerequisites</h2>
|
||||
|
||||
<p>
|
||||
You must follow the <a href="/doc/contribute.html#copyright">Go copyright
|
||||
rules</a> for all changes to the gccgo frontend and the associated
|
||||
libgo library. Code that is part of GCC rather than gccgo must follow
|
||||
the general <a href="http://gcc.gnu.org/contribute.html">GCC
|
||||
contribution rules</a>.
|
||||
You must follow the <a href="contribute.html#copyright">Go copyright
|
||||
rules.</a>
|
||||
</p>
|
||||
|
||||
<h2>Code</h2>
|
||||
|
||||
<p>
|
||||
The master sources for the gccgo frontend may be found at
|
||||
<a href="//code.google.com/p/gofrontend">http://code.google.com/p/gofrontend</a>.
|
||||
The master sources are not buildable by themselves, but only in
|
||||
conjunction with GCC (in the future, other compilers may be
|
||||
supported). Changes made to the gccgo frontend are also applied to
|
||||
the GCC source code repository hosted at <code>gcc.gnu.org</code>. In
|
||||
the <code>gofrontend</code> repository, the <code>go</code> directory
|
||||
is mirrored to the <code>gcc/go/gofrontend</code> directory in the GCC
|
||||
repository, and the <code>gofrontend</code> <code>libgo</code>
|
||||
directory is mirrored to the GCC <code>libgo</code> directory. In
|
||||
addition, the <code>test</code> directory
|
||||
from <a href="//code.google.com/p/go">the main Go repository</a>
|
||||
is mirrored to the <code>gcc/testsuite/go.test/test</code> directory
|
||||
in the GCC repository.
|
||||
The source code for the <code>gccgo</code> frontend may be found at
|
||||
<a href="http://code.google.com/p/gofrontend">http://code.google.com/p/gofrontend</a>.
|
||||
Changes made to that project are routinely merged into the source code
|
||||
hosted at <code>gcc.gnu.org</code>. The <code>gofrontend</code>
|
||||
project includes only the Go frontend proper. These are the files
|
||||
which in the <code>gcc</code> sources may be found in the
|
||||
directories <code>gcc/go</code> and <code>libgo</code>.
|
||||
The <code>gcc</code> sources also include a copy of
|
||||
the <code>test</code> directory
|
||||
from <a href="http://code.google.com/p/go">the main Go repository</a>.
|
||||
|
||||
<p>
|
||||
The frontend is written in C++ and as such the GNU coding standards do
|
||||
not entirely apply; in writing code for the frontend, follow the
|
||||
formatting of the surrounding code. Although the frontend is
|
||||
currently closely tied to the rest of the <code>gcc</code> codebase,
|
||||
we plan to make it more independent. Any new code that uses other
|
||||
parts of <code>gcc</code> should be placed in an appropriate file,
|
||||
such as <code>gogo-tree.cc</code>. Eventually
|
||||
all <code>gcc</code>-specific code should migrate to
|
||||
a <code>gcc-interface</code> subdirectory.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Changes to these directories always flow from the master sources to
|
||||
the GCC repository. The files should never be changed in the GCC
|
||||
repository except by changing them in the master sources and mirroring
|
||||
them.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The gccgo frontend is written in C++. It follows the GNU coding
|
||||
standards to the extent that they apply to C++. In writing code for
|
||||
the frontend, follow the formatting of the surrounding code. Although
|
||||
the frontend is currently tied to the rest of the GCC codebase, we
|
||||
plan to make it more independent. Eventually all GCC-specific code
|
||||
will migrate out of the frontend proper and into GCC proper. In the
|
||||
GCC sources this will generally mean moving code
|
||||
from <code>gcc/go/gofrontend</code> to <code>gcc/go</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The run-time library for gccgo is mostly the same as the library
|
||||
in <a href="//code.google.com/p/go">the main Go repository</a>.
|
||||
The library code in the Go repository is periodically merged into
|
||||
the <code>libgo/go</code> directory of the <code>gofrontend</code> and
|
||||
then the GCC repositories, using the shell
|
||||
script <code>libgo/merge.sh</code>. Accordingly, most library changes
|
||||
should be made in the main Go repository. The files outside
|
||||
of <code>libgo/go</code> are gccgo-specific; that said, some of the
|
||||
files in <code>libgo/runtime</code> are based on files
|
||||
in <code>src/runtime</code> in the main Go repository.
|
||||
The run-time library for <code>gccgo</code> is mostly the same as the
|
||||
library in <a href="http://code.google.com/p/go">the main Go
|
||||
repository</a>. The library code in the Go repository is periodically
|
||||
copied into the <code>gofrontend</code> and the <code>gcc</code>
|
||||
repositories. Accordingly, most library changes should be made in the
|
||||
main Go repository. Changes to the few <code>gccgo</code>-specific
|
||||
parts of the library should follow the process described here.
|
||||
The <code>gccgo</code>-specific parts of the library are everything in
|
||||
the <code>libgo</code> directory except for the <code>libgo/go</code>
|
||||
subdirectory.
|
||||
</p>
|
||||
|
||||
<h2>Testing</h2>
|
||||
|
||||
<p>
|
||||
All patches must be tested. A patch that introduces new failures is
|
||||
not acceptable.
|
||||
All patches must be tested. There are two test suites. A patch that
|
||||
introduces new failures is not acceptable.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
To run the gccgo test suite, run <code>make check-go</code> in your
|
||||
build directory. This will run various tests
|
||||
under <code>gcc/testsuite/go.*</code> and will also run
|
||||
the <code>libgo</code> testsuite. This copy of the tests from the
|
||||
main Go repository is run using the DejaGNU script found
|
||||
in <code>gcc/testsuite/go.test/go-test.exp</code>.
|
||||
To run the compiler test suite, run <code>make check-go</code> in the
|
||||
<code>gcc</code> subdirectory of your build directory. This will run
|
||||
various tests underneath <code>gcc/testsuite/go.*</code>. This
|
||||
includes a copy of the tests in the main Go repository, which are run
|
||||
using the DejaGNU script found in
|
||||
in <code>gcc/testsuite/go.test/go-test.exp</code>. Many of the
|
||||
compiler tests may be run without the Go library, but some do require
|
||||
the library to built first.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Most new tests should be submitted to the main Go repository for later
|
||||
mirroring into the GCC repository. If there is a need for specific
|
||||
tests for gccgo, they should go in
|
||||
To run the library test suite, run <code>make
|
||||
check-target-libgo</code> in the top level of your build directory.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Most new tests should be submitted to the main Go repository for
|
||||
copying into the <code>gccgo</code> repository. If there is a need
|
||||
for specific tests for <code>gccgo</code>, they should go in
|
||||
the <code>gcc/testsuite/go.go-torture</code>
|
||||
or <code>gcc/testsuite/go.dg</code> directories in the GCC repository.
|
||||
or <code>gcc/testsuite/go.dg</code> directories in
|
||||
the <code>gcc.gnu.org</code> repository.
|
||||
</p>
|
||||
|
||||
<h2>Submitting Changes</h2>
|
||||
|
||||
<p>
|
||||
Changes to the Go frontend should follow the same process as for the
|
||||
main Go repository, only for the <code>gofrontend</code> project and
|
||||
the<code>gofrontend-dev@googlegroups.com</code> mailing list
|
||||
rather than the <code>go</code> project and the
|
||||
<code>golang-dev@googlegroups.com</code> mailing list. Those changes
|
||||
will then be merged into the GCC sources.
|
||||
main Go repository, only for the <code>gofrontend</code> project
|
||||
rather than the <code>go</code> project. Those changes will then be
|
||||
merged into the <code>gcc</code> sources.
|
||||
</p>
|
||||
|
||||
@@ -1,71 +1,37 @@
|
||||
<!--{
|
||||
"Title": "Setting up and using gccgo",
|
||||
"Path": "/doc/install/gccgo"
|
||||
}-->
|
||||
<!-- Setting up and using gccgo -->
|
||||
|
||||
<p>
|
||||
This document explains how to use gccgo, a compiler for
|
||||
the Go language. The gccgo compiler is a new frontend
|
||||
for GCC, the widely used GNU compiler. Although the
|
||||
frontend itself is under a BSD-style license, gccgo is
|
||||
normally used as part of GCC and is then covered by
|
||||
This document explains how to use <code>gccgo</code>, a compiler for
|
||||
the Go language. The <code>gccgo</code> compiler is a new frontend
|
||||
for <code>gcc</code>, the widely used GNU compiler. Although the
|
||||
frontend itself is under a BSD-style license, <code>gccgo</code> is
|
||||
normally used as part of <code>gcc</code> and is then covered by
|
||||
the <a href="http://www.gnu.org/licenses/gpl.html">GNU General Public
|
||||
License</a> (the license covers gccgo itself as part of GCC; it
|
||||
does not cover code generated by gccgo).
|
||||
License</a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Note that gccgo is not the <code>gc</code> compiler; see
|
||||
the <a href="/doc/install.html">Installing Go</a> instructions for that
|
||||
Note that <code>gccgo</code> is not the <code>6g</code> compiler; see
|
||||
the <a href="install.html">Installing Go</a> instructions for that
|
||||
compiler.
|
||||
</p>
|
||||
|
||||
<h2 id="Releases">Releases</h2>
|
||||
|
||||
<p>
|
||||
The simplest way to install gccgo is to install a GCC binary release
|
||||
built to include Go support. GCC binary releases are available from
|
||||
<a href="http://gcc.gnu.org/install/binaries.html">various
|
||||
websites</a> and are typically included as part of GNU/Linux
|
||||
distributions. We expect that most people who build these binaries
|
||||
will include Go support.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The GCC 4.7.1 release and all later 4.7 releases include a complete
|
||||
<a href="/doc/go1.html">Go 1</a> compiler and libraries.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Due to timing, the GCC 4.8.0 and 4.8.1 releases are close to but not
|
||||
identical to Go 1.1. The GCC 4.8.2 release includes a complete Go
|
||||
1.1.2 implementation.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The GCC 4.9 releases include a complete Go 1.2 implementation.
|
||||
</p>
|
||||
|
||||
<h2 id="Source_code">Source code</h2>
|
||||
|
||||
<p>
|
||||
If you cannot use a release, or prefer to build gccgo for
|
||||
yourself,
|
||||
the gccgo source code is accessible via Subversion. The
|
||||
GCC web site
|
||||
The <code>gccgo</code> source code is accessible via Subversion. The
|
||||
<code>gcc</code> web site
|
||||
has <a href="http://gcc.gnu.org/svn.html">instructions for getting the
|
||||
GCC source code</a>. The gccgo source code is included. As a
|
||||
convenience, a stable version of the Go support is available in
|
||||
a branch of the main GCC code
|
||||
<code>gcc</code> source code</a>. The <code>gccgo</code> source code
|
||||
is a branch of the main <code>gcc</code> code
|
||||
repository: <code>svn://gcc.gnu.org/svn/gcc/branches/gccgo</code>.
|
||||
This branch is periodically updated with stable Go compiler sources.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Note that although <code>gcc.gnu.org</code> is the most convenient way
|
||||
to get the source code for the Go frontend, it is not where the master
|
||||
sources live. If you want to contribute changes to the Go frontend
|
||||
compiler, see <a href="/doc/gccgo_contribute.html">Contributing to
|
||||
to get the source code for the compiler, that is not where the master
|
||||
sources live. If you want to contribute changes to the gccgo
|
||||
compiler, see <a href="gccgo_contribute.html">Contributing to
|
||||
gccgo</a>.
|
||||
</p>
|
||||
|
||||
@@ -73,37 +39,29 @@ gccgo</a>.
|
||||
<h2 id="Building">Building</h2>
|
||||
|
||||
<p>
|
||||
Building gccgo is just like building GCC
|
||||
Building <code>gccgo</code> is just like building <code>gcc</code>
|
||||
with one or two additional options. See
|
||||
the <a href="http://gcc.gnu.org/install/">instructions on the gcc web
|
||||
site</a>. When you run <code>configure</code>, add the
|
||||
option <code>--enable-languages=c,c++,go</code> (along with other
|
||||
languages you may want to build). If you are targeting a 32-bit x86,
|
||||
then you will want to build gccgo to default to
|
||||
then you will want to build <code>gccgo</code> to default to
|
||||
supporting locked compare and exchange instructions; do this by also
|
||||
using the <code>configure</code> option <code>--with-arch=i586</code>
|
||||
(or a newer architecture, depending on where you need your programs to
|
||||
run). If you are targeting a 64-bit x86, but sometimes want to use
|
||||
the <code>-m32</code> option, then use the <code>configure</code>
|
||||
option <code>--with-arch-32=i586</code>.
|
||||
run).
|
||||
</p>
|
||||
|
||||
<h3 id="Gold">Gold</h3>
|
||||
|
||||
<p>
|
||||
On x86 GNU/Linux systems the gccgo compiler is able to
|
||||
On x86 GNU/Linux systems the <code>gccgo</code> compiler is able to
|
||||
use a small discontiguous stack for goroutines. This permits programs
|
||||
to run many more goroutines, since each goroutine can use a relatively
|
||||
small stack. Doing this requires using the gold linker version 2.22
|
||||
or later. You can either install GNU binutils 2.22 or later, or you
|
||||
can build gold yourself.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
To build gold yourself, build the GNU binutils,
|
||||
using <code>--enable-gold=default</code> when you run
|
||||
the <code>configure</code> script. Before building, you must install
|
||||
the flex and bison packages. A typical sequence would look like
|
||||
small stack. Doing this requires using a development version of
|
||||
the <code>gold</code> linker. The easiest way to do this is to build
|
||||
the GNU binutils, using <code>--enable-gold</code> when you run
|
||||
the <code>configure</code> script, and to
|
||||
use <code>--with-ld=GOLD_BINARY</code> when you
|
||||
configure <code>gccgo</code>. A typical sequence would look like
|
||||
this (you can replace <code>/opt/gold</code> with any directory to
|
||||
which you have write access):
|
||||
</p>
|
||||
@@ -111,81 +69,38 @@ which you have write access):
|
||||
<pre>
|
||||
cvs -z 9 -d :pserver:anoncvs@sourceware.org:/cvs/src login
|
||||
[password is "anoncvs"]
|
||||
[The next command will create a directory named src, not binutils]
|
||||
cvs -z 9 -d :pserver:anoncvs@sourceware.org:/cvs/src co binutils
|
||||
mkdir binutils-objdir
|
||||
cd binutils-objdir
|
||||
../src/configure --enable-gold=default --prefix=/opt/gold
|
||||
../src/configure --enable-gold --prefix=/opt/gold
|
||||
make
|
||||
make install
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
However you install gold, when you configure gccgo, use the
|
||||
option <code>--with-ld=<var>GOLD_BINARY</var></code>.
|
||||
</p>
|
||||
|
||||
<h3 id="Prerequisites">Prerequisites</h3>
|
||||
|
||||
<p>
|
||||
A number of prerequisites are required to build GCC, as
|
||||
described on
|
||||
the <a href="http://gcc.gnu.org/install/prerequisites.html">gcc web
|
||||
site</a>. It is important to install all the prerequisites before
|
||||
running the gcc <code>configure</code> script.
|
||||
The prerequisite libraries can be conveniently downloaded using the
|
||||
script <code>contrib/download_prerequisites</code> in the GCC sources.
|
||||
|
||||
<h3 id="Build_commands">Build commands</h3>
|
||||
|
||||
<p>
|
||||
Once all the prerequisites are installed, then a typical build and
|
||||
install sequence would look like this (only use
|
||||
the <code>--with-ld</code> option if you are using the gold linker as
|
||||
described above):
|
||||
A number of prerequisites are required to build <code>gcc</code>, as
|
||||
described on the <a href="http://gcc.gnu.org/">gcc web site</a>. If
|
||||
those are all available, then a typical build and install sequence
|
||||
would look like this (only use the <code>--with-ld</code> option if
|
||||
you built and installed the gold linker as described above):
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
svn checkout svn://gcc.gnu.org/svn/gcc/branches/gccgo gccgo
|
||||
mkdir objdir
|
||||
cd objdir
|
||||
../gccgo/configure --prefix=/opt/gccgo --enable-languages=c,c++,go --with-ld=/opt/gold/bin/ld
|
||||
../gccgo/configure --enable-languages=c,c++,go --with-ld=/opt/gold/bin/ld
|
||||
make
|
||||
make install
|
||||
</pre>
|
||||
|
||||
<h3 id="Ubuntu">A note on Ubuntu</h3>
|
||||
|
||||
<p>
|
||||
Current versions of Ubuntu and versions of GCC before 4.8 disagree on
|
||||
where system libraries and header files are found. This is not a
|
||||
gccgo issue. When building older versions of GCC, setting these
|
||||
environment variables while configuring and building gccgo may fix the
|
||||
problem.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
LIBRARY_PATH=/usr/lib/x86_64-linux-gnu
|
||||
C_INCLUDE_PATH=/usr/include/x86_64-linux-gnu
|
||||
CPLUS_INCLUDE_PATH=/usr/include/x86_64-linux-gnu
|
||||
export LIBRARY_PATH C_INCLUDE_PATH CPLUS_INCLUDE_PATH
|
||||
</pre>
|
||||
|
||||
<h2 id="Using_gccgo">Using gccgo</h2>
|
||||
|
||||
<p>
|
||||
The gccgo compiler works like other gcc frontends. The gccgo
|
||||
installation does not currently include a version of
|
||||
the <code>go</code> command. However if you have the <code>go</code>
|
||||
command from an installation of the <code>gc</code> compiler, you can
|
||||
use it with gccgo by passing the option <code>-compiler gccgo</code>
|
||||
to <code>go build</code> or <code>go install</code> or <code>go
|
||||
test</code>.
|
||||
</p>
|
||||
The <code>gccgo</code> compiler works like other gcc frontends.
|
||||
|
||||
<p>
|
||||
To compile a file without using the <code>go</code> command:
|
||||
</p>
|
||||
To compile a file:
|
||||
|
||||
<pre>
|
||||
gccgo -c file.go
|
||||
@@ -194,7 +109,6 @@ gccgo -c file.go
|
||||
<p>
|
||||
That produces <code>file.o</code>. To link files together to form an
|
||||
executable:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
gccgo -o file file.o
|
||||
@@ -202,68 +116,44 @@ gccgo -o file file.o
|
||||
|
||||
<p>
|
||||
To run the resulting file, you will need to tell the program where to
|
||||
find the compiled Go packages. There are a few ways to do this:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>
|
||||
Set the <code>LD_LIBRARY_PATH</code> environment variable:
|
||||
</p>
|
||||
find the compiled Go packages. This can be done either by setting
|
||||
<code>LD_LIBRARY_PATH</code> in your environment:
|
||||
|
||||
<pre>
|
||||
LD_LIBRARY_PATH=${prefix}/lib/gcc/MACHINE/VERSION
|
||||
[or]
|
||||
LD_LIBRARY_PATH=${prefix}/lib64/gcc/MACHINE/VERSION
|
||||
export LD_LIBRARY_PATH
|
||||
LD_LIBRARY_PATH=/usr/lib/gcc/MACHINE/VERSION
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Here <code>${prefix}</code> is the <code>--prefix</code> option used
|
||||
when building gccgo. For a binary install this is
|
||||
normally <code>/usr</code>. Whether to use <code>lib</code>
|
||||
or <code>lib64</code> depends on the target.
|
||||
Typically <code>lib64</code> is correct for x86_64 systems,
|
||||
and <code>lib</code> is correct for other systems. The idea is to
|
||||
name the directory where <code>libgo.so</code> is found.
|
||||
</p>
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<p>
|
||||
Passing a <code>-Wl,-R</code> option when you link:
|
||||
</p>
|
||||
or by passing a <code>-Wl,-R</code> option when you link:
|
||||
|
||||
<pre>
|
||||
gccgo -o file file.o -Wl,-R,${prefix}/lib/gcc/MACHINE/VERSION
|
||||
[or]
|
||||
gccgo -o file file.o -Wl,-R,${prefix}/lib64/gcc/MACHINE/VERSION
|
||||
gccgo -o file file.o -Wl,-R,/usr/lib/gcc/MACHINE/VERSION
|
||||
</pre>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<p>
|
||||
Use the <code>-static-libgo</code> option to link statically against
|
||||
the compiled packages.
|
||||
</p>
|
||||
</li>
|
||||
or you can use the <code>-static-libgo</code> link-time option to link
|
||||
statically against libgo, or you can do a fully static link (static
|
||||
linking is the default for the <code>6l</code> Go linker). On most
|
||||
systems, a static link will look something like:
|
||||
|
||||
<pre>
|
||||
gccgo -o file file.o -static -L /usr/lib/nptl -lgobegin -lgo -lpthread
|
||||
</pre>
|
||||
|
||||
<li>
|
||||
<p>
|
||||
Use the <code>-static</code> option to do a fully static link (the
|
||||
default for the <code>gc</code> compiler).
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
You may get a warning about not creating an <code>.eh_frame_hdr</code>
|
||||
section; this has nothing to do with Go, and may be ignored. In the
|
||||
future the requirement of explicitly specifying
|
||||
<code>-L /usr/lib/nptl -lgobegin -lgo -lpthread</code>
|
||||
may be removed.
|
||||
|
||||
|
||||
<h2 id="Options">Options</h2>
|
||||
|
||||
<p>
|
||||
The gccgo compiler supports all GCC options
|
||||
The <code>gccgo</code> compiler supports all <code>gcc</code> options
|
||||
that are language independent, notably the <code>-O</code>
|
||||
and <code>-g</code> options.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The <code>-fgo-prefix=PREFIX</code> option may be used to set a unique
|
||||
@@ -272,57 +162,57 @@ use with large programs that contain many packages, in order to allow
|
||||
multiple packages to use the same identifier as the package name.
|
||||
The <code>PREFIX</code> may be any string; a good choice for the
|
||||
string is the directory where the package will be installed.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The <code>-fno-require-return-statement</code> option may be used to
|
||||
disable the compiler error about functions missing return statements.
|
||||
Note that there is no way to disable this error in <code>6g</code>.
|
||||
|
||||
<p>
|
||||
The <code>-I</code> and <code>-L</code> options, which are synonyms
|
||||
for the compiler, may be used to set the search path for finding
|
||||
imports.
|
||||
</p>
|
||||
|
||||
|
||||
<h2 id="Imports">Imports</h2>
|
||||
|
||||
<p>
|
||||
When you compile a file that exports something, the export
|
||||
information will be stored directly in the object file. When
|
||||
you import a package, you must tell gccgo how to
|
||||
When you compile a file which exports something, the export
|
||||
information will be stored directly in the object file. When
|
||||
you import a package, you must tell <code>gccgo</code> how to
|
||||
find the file.
|
||||
|
||||
<p>
|
||||
When you import the package <var>FILE</var> with gccgo,
|
||||
When you import the package <var>FILE</var> with <code>gccgo</code>,
|
||||
it will look for the import data in the following files, and use the
|
||||
first one that it finds.
|
||||
|
||||
<ul>
|
||||
<li><code><var>FILE</var>.gox</code>
|
||||
<li><code><var>FILE</var>.o</code>
|
||||
<li><code>lib<var>FILE</var>.so</code>
|
||||
<li><code>lib<var>FILE</var>.a</code>
|
||||
<li><code><var>FILE</var>.o</code>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
<code><var>FILE</var>.gox</code>, when used, will typically contain
|
||||
nothing but export data. This can be generated from
|
||||
<code><var>FILE</var>.o</code> via
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
objcopy -j .go_export FILE.o FILE.gox
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The gccgo compiler will look in the current
|
||||
directory for import files. In more complex scenarios you
|
||||
The <code>gccgo</code> compiler will look in the current
|
||||
directory for import files. In more complex scenarios you
|
||||
may pass the <code>-I</code> or <code>-L</code> option to
|
||||
gccgo. Both options take directories to search. The
|
||||
<code>gccgo</code>. Both options take directories to search. The
|
||||
<code>-L</code> option is also passed to the linker.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The gccgo compiler does not currently (2013-06-20) record
|
||||
The <code>gccgo</code> compiler does not currently (2009-11-06) record
|
||||
the file name of imported packages in the object file. You must
|
||||
arrange for the imported data to be linked into the program.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
gccgo -c mypackage.go # Exports mypackage
|
||||
@@ -330,41 +220,48 @@ gccgo -c main.go # Imports mypackage
|
||||
gccgo -o main main.o mypackage.o # Explicitly links with mypackage.o
|
||||
</pre>
|
||||
|
||||
<h2 id="Unimplemented">Unimplemented</h2>
|
||||
|
||||
<p>
|
||||
Some Go features are not yet implemented in <code>gccgo</code>. As of
|
||||
2010-08-23, the following are not implemented:
|
||||
|
||||
<ul>
|
||||
<li>goroutines are implemented as NPTL threads. If you can not use
|
||||
the gold linker as described above, they are created with a fixed
|
||||
stack size, and the number of goroutines that may be created at
|
||||
one time is limited.
|
||||
</ul>
|
||||
|
||||
<h2 id="Debugging">Debugging</h2>
|
||||
|
||||
<p>
|
||||
If you use the <code>-g</code> option when you compile, you can run
|
||||
<code>gdb</code> on your executable. The debugger has only limited
|
||||
knowledge about Go. You can set breakpoints, single-step,
|
||||
<code>gdb</code> on your executable. The debugger doesn't (yet)
|
||||
know anything about Go. However, you can set breakpoints, single-step,
|
||||
etc. You can print variables, but they will be printed as though they
|
||||
had C/C++ types. For numeric types this doesn't matter. Go strings
|
||||
and interfaces will show up as two-element structures. Go
|
||||
maps and channels are always represented as C pointers to run-time
|
||||
structures.
|
||||
</p>
|
||||
had C/C++ types. For numeric types this doesn't matter. Go strings
|
||||
will show up as pointers to structures; to see the value
|
||||
<code>print *stringvar</code>. In general Go strings, maps, channels
|
||||
and interfaces are always represented as C pointers.
|
||||
|
||||
<h2 id="C_Interoperability">C Interoperability</h2>
|
||||
|
||||
<p>
|
||||
When using gccgo there is limited interoperability with C,
|
||||
When using <code>gccgo</code> there is limited interoperability with C,
|
||||
or with C++ code compiled using <code>extern "C"</code>.
|
||||
</p>
|
||||
|
||||
<h3 id="Types">Types</h3>
|
||||
|
||||
<p>
|
||||
Basic types map directly: an <code>int</code> in Go is an <code>int</code>
|
||||
in C, an <code>int32</code> is an <code>int32_t</code>,
|
||||
etc. Go <code>byte</code> is equivalent to C <code>unsigned
|
||||
char</code>.
|
||||
in C, etc. Go <code>byte</code> is equivalent to C <code>unsigned char</code>.
|
||||
Pointers in Go are pointers in C. A Go <code>struct</code> is the same as C
|
||||
<code>struct</code> with the same fields and types.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The Go <code>string</code> type is currently defined as a two-element
|
||||
structure (this is <b style="color: red;">subject to change</b>):
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
struct __go_string {
|
||||
@@ -379,12 +276,10 @@ array in Go is equivalent to a C pointer to the
|
||||
equivalent of the element type.
|
||||
For example, Go <code>*[10]int</code> is equivalent to C <code>int*</code>,
|
||||
assuming that the C pointer does point to 10 elements.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
A slice in Go is a structure. The current definition is
|
||||
(this is <b style="color: red;">subject to change</b>):
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
struct __go_slice {
|
||||
@@ -395,23 +290,20 @@ struct __go_slice {
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The type of a Go function is a pointer to a struct (this is
|
||||
<b style="color: red;">subject to change</b>). The first field in the
|
||||
struct points to the code of the function, which will be equivalent to
|
||||
a pointer to a C function whose parameter types are equivalent, with
|
||||
an additional trailing parameter. The trailing parameter is the
|
||||
closure, and the argument to pass is a pointer to the Go function
|
||||
struct.
|
||||
|
||||
When a Go function returns more than one value, the C function returns
|
||||
a struct. For example, these functions are roughly equivalent:
|
||||
</p>
|
||||
The type of a Go function with no receiver is equivalent to a C function
|
||||
whose parameter types are equivalent. When a Go function returns more
|
||||
than one value, the C function returns a struct. For example, these
|
||||
functions have equivalent types:
|
||||
|
||||
<pre>
|
||||
func GoFunction(int) (int, float64)
|
||||
struct { int i; float64 f; } CFunction(int, void*)
|
||||
struct { int i; float64 f; } CFunction(int)
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
A pointer to a Go function is equivalent to a pointer to a C function
|
||||
when the functions have equivalent types.
|
||||
|
||||
<p>
|
||||
Go <code>interface</code>, <code>channel</code>, and <code>map</code>
|
||||
types have no corresponding C type (<code>interface</code> is a
|
||||
@@ -422,7 +314,6 @@ which one is difficult to predict in general; use a cast. C <code>union</code>
|
||||
types have no corresponding Go type. C <code>struct</code> types containing
|
||||
bitfields have no corresponding Go type. C++ <code>class</code> types have
|
||||
no corresponding Go type.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Memory allocation is completely different between C and Go, as Go uses
|
||||
@@ -434,56 +325,43 @@ while the Go side still has a copy the program will fail. When passing a
|
||||
pointer from Go to C, the Go function must retain a visible copy of it in
|
||||
some Go variable. Otherwise the Go garbage collector may delete the
|
||||
pointer while the C function is still using it.
|
||||
</p>
|
||||
|
||||
<h3 id="Function_names">Function names</h3>
|
||||
|
||||
<p>
|
||||
Go code can call C functions directly using a Go extension implemented
|
||||
in gccgo: a function declaration may be preceded by
|
||||
<code>//extern NAME</code>. For example, here is how the C function
|
||||
in <code>gccgo</code>: a function declaration may be followed by
|
||||
<code>__asm__("NAME")</code>. For example, here is how the C function
|
||||
<code>open</code> can be declared in Go:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
//extern open
|
||||
func c_open(name *byte, mode int, perm int) int
|
||||
func c_open(name *byte, mode int, perm int) int __asm__ ("open");
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The C function naturally expects a NUL-terminated string, which in
|
||||
The C function naturally expects a nul terminated string, which in
|
||||
Go is equivalent to a pointer to an array (not a slice!) of
|
||||
<code>byte</code> with a terminating zero byte. So a sample call
|
||||
from Go would look like (after importing the <code>syscall</code> package):
|
||||
</p>
|
||||
from Go would look like (after importing the <code>os</code> package):
|
||||
|
||||
<pre>
|
||||
var name = [4]byte{'f', 'o', 'o', 0};
|
||||
i := c_open(&name[0], syscall.O_RDONLY, 0);
|
||||
i := c_open(&name[0], os.O_RDONLY, 0);
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
(this serves as an example only, to open a file in Go please use Go's
|
||||
<code>os.Open</code> function instead).
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Note that if the C function can block, such as in a call
|
||||
to <code>read</code>, calling the C function may block the Go program.
|
||||
Unless you have a clear understanding of what you are doing, all calls
|
||||
between C and Go should be implemented through cgo or SWIG, as for
|
||||
the <code>gc</code> compiler.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The name of Go functions accessed from C is subject to change. At present
|
||||
the name of a Go function that does not have a receiver is
|
||||
<code>prefix.package.Functionname</code>. The prefix is set by
|
||||
the <code>-fgo-prefix</code> option used when the package is compiled;
|
||||
if the option is not used, the default is <code>go</code>.
|
||||
if the option is not used, the default is simply <code>go</code>.
|
||||
To call the function from C you must set the name using
|
||||
a GCC extension.
|
||||
</p>
|
||||
a <code>gcc</code> extension similar to the <code>gccgo</code>
|
||||
extension.
|
||||
|
||||
<pre>
|
||||
extern int go_function(int) __asm__ ("myprefix.mypackage.Function");
|
||||
@@ -493,37 +371,39 @@ extern int go_function(int) __asm__ ("myprefix.mypackage.Function");
|
||||
Automatic generation of Go declarations from C source code</h3>
|
||||
|
||||
<p>
|
||||
The Go version of GCC supports automatically generating
|
||||
Go declarations from C code. The facility is rather awkward, and most
|
||||
users should use the <a href="/cmd/cgo">cgo</a> program with
|
||||
the <code>-gccgo</code> option instead.
|
||||
</p>
|
||||
The Go version of <code>gcc</code> supports automatically generating
|
||||
Go declarations from C code. The facility is rather awkward at present,
|
||||
and a better mechanism is under development.
|
||||
|
||||
<p>
|
||||
Compile your C code as usual, and add the option
|
||||
<code>-fdump-go-spec=<var>FILENAME</var></code>. This will create the
|
||||
file <code><var>FILENAME</var></code> as a side effect of the
|
||||
compilation. This file will contain Go declarations for the types,
|
||||
variables and functions declared in the C code. C types that can not
|
||||
be represented in Go will be recorded as comments in the Go code. The
|
||||
generated file will not have a <code>package</code> declaration, but
|
||||
can otherwise be compiled directly by gccgo.
|
||||
</p>
|
||||
Compile your C code as usual, but replace <code>-c</code> with
|
||||
<code>-S -ggo</code>. The result will be an assembler file
|
||||
with a <code>.s</code> extension. This assembler file will contain
|
||||
comments beginning with #GO. Those comments are declarations in the Go
|
||||
language for the C types, variables and functions declared in the C code.
|
||||
C types which can not be represented in Go will contain the string INVALID.
|
||||
Unsupported macro definitions will be recorded as <code>unknowndefine</code>,
|
||||
and uses of <code>#undef</code> will be recorded as <code>undef</code>.
|
||||
So it is very approximately possible to get Go code by running
|
||||
|
||||
<pre>
|
||||
gcc -S -ggo foo.c
|
||||
grep '#GO' foo.s | grep -v INVALID | grep -v unknowndefine | grep -v undef > foo.go
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
This procedure is full of unstated caveats and restrictions and we make no
|
||||
guarantee that it will not change in the future. It is more useful as a
|
||||
starting point for real Go code than as a regular procedure.
|
||||
</p>
|
||||
|
||||
<h2 id="RTEMS_Port">RTEMS Port</h2>
|
||||
<p>
|
||||
The gccgo compiler has been ported to <a href="http://www.rtems.com/">
|
||||
The <code>gccgo</code> compiler has been ported to <a href="http://www.rtems.com/">
|
||||
<code>RTEMS</code></a>. <code>RTEMS</code> is a real-time executive
|
||||
that provides a high performance environment for embedded applications
|
||||
on a range of processors and embedded hardware. The current gccgo
|
||||
on a range of processors and embedded hardware. The current <code>gccgo</code>
|
||||
port is for x86. The goal is to extend the port to most of the
|
||||
<a href="http://www.rtems.org/wiki/index.php/SupportedCPUs">
|
||||
architectures supported by <code>RTEMS</code></a>. For more information on the port,
|
||||
as well as instructions on how to install it, please see this
|
||||
<a href="http://www.rtems.org/wiki/index.php/GCCGoRTEMS"><code>RTEMS</code> Wiki page</a>.
|
||||
<a href="http://www.rtems.com/wiki/index.php/GCCGoRTEMS"><code>RTEMS</code> Wiki page</a>.
|
||||
|
||||
|
Before Width: | Height: | Size: 8.6 KiB After Width: | Height: | Size: 8.6 KiB |
|
Before Width: | Height: | Size: 9.1 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 25 KiB |
1099
doc/go1.1.html
979
doc/go1.2.html
@@ -1,979 +0,0 @@
|
||||
<!--{
|
||||
"Title": "Go 1.2 Release Notes",
|
||||
"Path": "/doc/go1.2",
|
||||
"Template": true
|
||||
}-->
|
||||
|
||||
<h2 id="introduction">Introduction to Go 1.2</h2>
|
||||
|
||||
<p>
|
||||
Since the release of <a href="/doc/go1.1.html">Go version 1.1</a> in April, 2013,
|
||||
the release schedule has been shortened to make the release process more efficient.
|
||||
This release, Go version 1.2 or Go 1.2 for short, arrives roughly six months after 1.1,
|
||||
while 1.1 took over a year to appear after 1.0.
|
||||
Because of the shorter time scale, 1.2 is a smaller delta than the step from 1.0 to 1.1,
|
||||
but it still has some significant developments, including
|
||||
a better scheduler and one new language feature.
|
||||
Of course, Go 1.2 keeps the <a href="/doc/go1compat.html">promise
|
||||
of compatibility</a>.
|
||||
The overwhelming majority of programs built with Go 1.1 (or 1.0 for that matter)
|
||||
will run without any changes whatsoever when moved to 1.2,
|
||||
although the introduction of one restriction
|
||||
to a corner of the language may expose already-incorrect code
|
||||
(see the discussion of the <a href="#use_of_nil">use of nil</a>).
|
||||
</p>
|
||||
|
||||
<h2 id="language">Changes to the language</h2>
|
||||
|
||||
<p>
|
||||
In the interest of firming up the specification, one corner case has been clarified,
|
||||
with consequences for programs.
|
||||
There is also one new language feature.
|
||||
</p>
|
||||
|
||||
<h3 id="use_of_nil">Use of nil</h3>
|
||||
|
||||
<p>
|
||||
The language now specifies that, for safety reasons,
|
||||
certain uses of nil pointers are guaranteed to trigger a run-time panic.
|
||||
For instance, in Go 1.0, given code like
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
type T struct {
|
||||
X [1<<24]byte
|
||||
Field int32
|
||||
}
|
||||
|
||||
func main() {
|
||||
var x *T
|
||||
...
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
the <code>nil</code> pointer <code>x</code> could be used to access memory incorrectly:
|
||||
the expression <code>x.Field</code> could access memory at address <code>1<<24</code>.
|
||||
To prevent such unsafe behavior, in Go 1.2 the compilers now guarantee that any indirection through
|
||||
a nil pointer, such as illustrated here but also in nil pointers to arrays, nil interface values,
|
||||
nil slices, and so on, will either panic or return a correct, safe non-nil value.
|
||||
In short, any expression that explicitly or implicitly requires evaluation of a nil address is an error.
|
||||
The implementation may inject extra tests into the compiled program to enforce this behavior.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Further details are in the
|
||||
<a href="//golang.org/s/go12nil">design document</a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<em>Updating</em>:
|
||||
Most code that depended on the old behavior is erroneous and will fail when run.
|
||||
Such programs will need to be updated by hand.
|
||||
</p>
|
||||
|
||||
<h3 id="three_index">Three-index slices</h3>
|
||||
|
||||
<p>
|
||||
Go 1.2 adds the ability to specify the capacity as well as the length when using a slicing operation
|
||||
on an existing array or slice.
|
||||
A slicing operation creates a new slice by describing a contiguous section of an already-created array or slice:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
var array [10]int
|
||||
slice := array[2:4]
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The capacity of the slice is the maximum number of elements that the slice may hold, even after reslicing;
|
||||
it reflects the size of the underlying array.
|
||||
In this example, the capacity of the <code>slice</code> variable is 8.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Go 1.2 adds new syntax to allow a slicing operation to specify the capacity as well as the length.
|
||||
A second
|
||||
colon introduces the capacity value, which must be less than or equal to the capacity of the
|
||||
source slice or array, adjusted for the origin. For instance,
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
slice = array[2:4:7]
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
sets the slice to have the same length as in the earlier example but its capacity is now only 5 elements (7-2).
|
||||
It is impossible to use this new slice value to access the last three elements of the original array.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
In this three-index notation, a missing first index (<code>[:i:j]</code>) defaults to zero but the other
|
||||
two indices must always be specified explicitly.
|
||||
It is possible that future releases of Go may introduce default values for these indices.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Further details are in the
|
||||
<a href="//golang.org/s/go12slice">design document</a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<em>Updating</em>:
|
||||
This is a backwards-compatible change that affects no existing programs.
|
||||
</p>
|
||||
|
||||
<h2 id="impl">Changes to the implementations and tools</h2>
|
||||
|
||||
<h3 id="preemption">Pre-emption in the scheduler</h3>
|
||||
|
||||
<p>
|
||||
In prior releases, a goroutine that was looping forever could starve out other
|
||||
goroutines on the same thread, a serious problem when GOMAXPROCS
|
||||
provided only one user thread.
|
||||
In Go 1.2, this is partially addressed: The scheduler is invoked occasionally
|
||||
upon entry to a function.
|
||||
This means that any loop that includes a (non-inlined) function call can
|
||||
be pre-empted, allowing other goroutines to run on the same thread.
|
||||
</p>
|
||||
|
||||
<h3 id="thread_limit">Limit on the number of threads</h3>
|
||||
|
||||
<p>
|
||||
Go 1.2 introduces a configurable limit (default 10,000) to the total number of threads
|
||||
a single program may have in its address space, to avoid resource starvation
|
||||
issues in some environments.
|
||||
Note that goroutines are multiplexed onto threads so this limit does not directly
|
||||
limit the number of goroutines, only the number that may be simultaneously blocked
|
||||
in a system call.
|
||||
In practice, the limit is hard to reach.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The new <a href="/pkg/runtime/debug/#SetMaxThreads"><code>SetMaxThreads</code></a> function in the
|
||||
<a href="/pkg/runtime/debug/"><code>runtime/debug</code></a> package controls the thread count limit.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<em>Updating</em>:
|
||||
Few functions will be affected by the limit, but if a program dies because it hits the
|
||||
limit, it could be modified to call <code>SetMaxThreads</code> to set a higher count.
|
||||
Even better would be to refactor the program to need fewer threads, reducing consumption
|
||||
of kernel resources.
|
||||
</p>
|
||||
|
||||
<h3 id="stack_size">Stack size</h3>
|
||||
|
||||
<p>
|
||||
In Go 1.2, the minimum size of the stack when a goroutine is created has been lifted from 4KB to 8KB.
|
||||
Many programs were suffering performance problems with the old size, which had a tendency
|
||||
to introduce expensive stack-segment switching in performance-critical sections.
|
||||
The new number was determined by empirical testing.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
At the other end, the new function <a href="/pkg/runtime/debug/#SetMaxStack"><code>SetMaxStack</code></a>
|
||||
in the <a href="/pkg/runtime/debug"><code>runtime/debug</code></a> package controls
|
||||
the <em>maximum</em> size of a single goroutine's stack.
|
||||
The default is 1GB on 64-bit systems and 250MB on 32-bit systems.
|
||||
Before Go 1.2, it was too easy for a runaway recursion to consume all the memory on a machine.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<em>Updating</em>:
|
||||
The increased minimum stack size may cause programs with many goroutines to use
|
||||
more memory. There is no workaround, but plans for future releases
|
||||
include new stack management technology that should address the problem better.
|
||||
</p>
|
||||
|
||||
<h3 id="cgo_and_cpp">Cgo and C++</h3>
|
||||
|
||||
<p>
|
||||
The <a href="/cmd/cgo/"><code>cgo</code></a> command will now invoke the C++
|
||||
compiler to build any pieces of the linked-to library that are written in C++;
|
||||
<a href="/cmd/cgo/">the documentation</a> has more detail.
|
||||
</p>
|
||||
|
||||
<h3 id="go_tools_godoc">Godoc and vet moved to the go.tools subrepository</h3>
|
||||
|
||||
<p>
|
||||
Both binaries are still included with the distribution, but the source code for the
|
||||
godoc and vet commands has moved to the
|
||||
<a href="//code.google.com/p/go.tools">go.tools</a> subrepository.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Also, the core of the godoc program has been split into a
|
||||
<a href="https://code.google.com/p/go/source/browse/?repo=tools#hg%2Fgodoc">library</a>,
|
||||
while the command itself is in a separate
|
||||
<a href="https://code.google.com/p/go/source/browse/?repo=tools#hg%2Fcmd%2Fgodoc">directory</a>.
|
||||
The move allows the code to be updated easily and the separation into a library and command
|
||||
makes it easier to construct custom binaries for local sites and different deployment methods.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<em>Updating</em>:
|
||||
Since godoc and vet are not part of the library,
|
||||
no client Go code depends on the their source and no updating is required.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The binary distributions available from <a href="//golang.org">golang.org</a>
|
||||
include these binaries, so users of these distributions are unaffected.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
When building from source, users must use "go get" to install godoc and vet.
|
||||
(The binaries will continue to be installed in their usual locations, not
|
||||
<code>$GOPATH/bin</code>.)
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
$ go get code.google.com/p/go.tools/cmd/godoc
|
||||
$ go get code.google.com/p/go.tools/cmd/vet
|
||||
</pre>
|
||||
|
||||
<h3 id="gccgo">Status of gccgo</h3>
|
||||
|
||||
<p>
|
||||
We expect the future GCC 4.9 release to include gccgo with full
|
||||
support for Go 1.2.
|
||||
In the current (4.8.2) release of GCC, gccgo implements Go 1.1.2.
|
||||
</p>
|
||||
|
||||
<h3 id="gc_changes">Changes to the gc compiler and linker</h3>
|
||||
|
||||
<p>
|
||||
Go 1.2 has several semantic changes to the workings of the gc compiler suite.
|
||||
Most users will be unaffected by them.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The <a href="/cmd/cgo/"><code>cgo</code></a> command now
|
||||
works when C++ is included in the library being linked against.
|
||||
See the <a href="/cmd/cgo/"><code>cgo</code></a> documentation
|
||||
for details.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The gc compiler displayed a vestigial detail of its origins when
|
||||
a program had no <code>package</code> clause: it assumed
|
||||
the file was in package <code>main</code>.
|
||||
The past has been erased, and a missing <code>package</code> clause
|
||||
is now an error.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
On the ARM, the toolchain supports "external linking", which
|
||||
is a step towards being able to build shared libraries with the gc
|
||||
tool chain and to provide dynamic linking support for environments
|
||||
in which that is necessary.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
In the runtime for the ARM, with <code>5a</code>, it used to be possible to refer
|
||||
to the runtime-internal <code>m</code> (machine) and <code>g</code>
|
||||
(goroutine) variables using <code>R9</code> and <code>R10</code> directly.
|
||||
It is now necessary to refer to them by their proper names.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Also on the ARM, the <code>5l</code> linker (sic) now defines the
|
||||
<code>MOVBS</code> and <code>MOVHS</code> instructions
|
||||
as synonyms of <code>MOVB</code> and <code>MOVH</code>,
|
||||
to make clearer the separation between signed and unsigned
|
||||
sub-word moves; the unsigned versions already existed with a
|
||||
<code>U</code> suffix.
|
||||
</p>
|
||||
|
||||
<h3 id="cover">Test coverage</h3>
|
||||
|
||||
<p>
|
||||
One major new feature of <a href="/pkg/go/"><code>go test</code></a> is
|
||||
that it can now compute and, with help from a new, separately installed
|
||||
"go tool cover" program, display test coverage results.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The cover tool is part of the
|
||||
<a href="https://code.google.com/p/go/source/checkout?repo=tools"><code>go.tools</code></a>
|
||||
subrepository.
|
||||
It can be installed by running
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
$ go get code.google.com/p/go.tools/cmd/cover
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The cover tool does two things.
|
||||
First, when "go test" is given the <code>-cover</code> flag, it is run automatically
|
||||
to rewrite the source for the package and insert instrumentation statements.
|
||||
The test is then compiled and run as usual, and basic coverage statistics are reported:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
$ go test -cover fmt
|
||||
ok fmt 0.060s coverage: 91.4% of statements
|
||||
$
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Second, for more detailed reports, different flags to "go test" can create a coverage profile file,
|
||||
which the cover program, invoked with "go tool cover", can then analyze.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Details on how to generate and analyze coverage statistics can be found by running the commands
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
$ go help testflag
|
||||
$ go tool cover -help
|
||||
</pre>
|
||||
|
||||
<h3 id="go_doc">The go doc command is deleted</h3>
|
||||
|
||||
<p>
|
||||
The "go doc" command is deleted.
|
||||
Note that the <a href="/cmd/godoc/"><code>godoc</code></a> tool itself is not deleted,
|
||||
just the wrapping of it by the <a href="/cmd/go/"><code>go</code></a> command.
|
||||
All it did was show the documents for a package by package path,
|
||||
which godoc itself already does with more flexibility.
|
||||
It has therefore been deleted to reduce the number of documentation tools and,
|
||||
as part of the restructuring of godoc, encourage better options in future.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<em>Updating</em>: For those who still need the precise functionality of running
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
$ go doc
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
in a directory, the behavior is identical to running
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
$ godoc .
|
||||
</pre>
|
||||
|
||||
<h3 id="gocmd">Changes to the go command</h3>
|
||||
|
||||
<p>
|
||||
The <a href="/cmd/go/"><code>go get</code></a> command
|
||||
now has a <code>-t</code> flag that causes it to download the dependencies
|
||||
of the tests run by the package, not just those of the package itself.
|
||||
By default, as before, dependencies of the tests are not downloaded.
|
||||
</p>
|
||||
|
||||
<h2 id="performance">Performance</h2>
|
||||
|
||||
<p>
|
||||
There are a number of significant performance improvements in the standard library; here are a few of them.
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/compress/bzip2/"><code>compress/bzip2</code></a>
|
||||
decompresses about 30% faster.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/crypto/des/"><code>crypto/des</code></a> package
|
||||
is about five times faster.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/encoding/json/"><code>encoding/json</code></a> package
|
||||
encodes about 30% faster.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
Networking performance on Windows and BSD systems is about 30% faster through the use
|
||||
of an integrated network poller in the runtime, similar to what was done for Linux and OS X
|
||||
in Go 1.1.
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
<h2 id="library">Changes to the standard library</h2>
|
||||
|
||||
|
||||
<h3 id="archive_tar_zip">The archive/tar and archive/zip packages</h3>
|
||||
|
||||
<p>
|
||||
The
|
||||
<a href="/pkg/archive/tar/"><code>archive/tar</code></a>
|
||||
and
|
||||
<a href="/pkg/archive/zip/"><code>archive/zip</code></a>
|
||||
packages have had a change to their semantics that may break existing programs.
|
||||
The issue is that they both provided an implementation of the
|
||||
<a href="/pkg/os/#FileInfo"><code>os.FileInfo</code></a>
|
||||
interface that was not compliant with the specification for that interface.
|
||||
In particular, their <code>Name</code> method returned the full
|
||||
path name of the entry, but the interface specification requires that
|
||||
the method return only the base name (final path element).
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<em>Updating</em>: Since this behavior was newly implemented and
|
||||
a bit obscure, it is possible that no code depends on the broken behavior.
|
||||
If there are programs that do depend on it, they will need to be identified
|
||||
and fixed manually.
|
||||
</p>
|
||||
|
||||
<h3 id="encoding">The new encoding package</h3>
|
||||
|
||||
<p>
|
||||
There is a new package, <a href="/pkg/encoding/"><code>encoding</code></a>,
|
||||
that defines a set of standard encoding interfaces that may be used to
|
||||
build custom marshalers and unmarshalers for packages such as
|
||||
<a href="/pkg/encoding/xml/"><code>encoding/xml</code></a>,
|
||||
<a href="/pkg/encoding/json/"><code>encoding/json</code></a>,
|
||||
and
|
||||
<a href="/pkg/encoding/binary/"><code>encoding/binary</code></a>.
|
||||
These new interfaces have been used to tidy up some implementations in
|
||||
the standard library.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The new interfaces are called
|
||||
<a href="/pkg/encoding/#BinaryMarshaler"><code>BinaryMarshaler</code></a>,
|
||||
<a href="/pkg/encoding/#BinaryUnmarshaler"><code>BinaryUnmarshaler</code></a>,
|
||||
<a href="/pkg/encoding/#TextMarshaler"><code>TextMarshaler</code></a>,
|
||||
and
|
||||
<a href="/pkg/encoding/#TextUnmarshaler"><code>TextUnmarshaler</code></a>.
|
||||
Full details are in the <a href="/pkg/encoding/">documentation</a> for the package
|
||||
and a separate <a href="//golang.org/s/go12encoding">design document</a>.
|
||||
</p>
|
||||
|
||||
<h3 id="fmt_indexed_arguments">The fmt package</h3>
|
||||
|
||||
<p>
|
||||
The <a href="/pkg/fmt/"><code>fmt</code></a> package's formatted print
|
||||
routines such as <a href="/pkg/fmt/#Printf"><code>Printf</code></a>
|
||||
now allow the data items to be printed to be accessed in arbitrary order
|
||||
by using an indexing operation in the formatting specifications.
|
||||
Wherever an argument is to be fetched from the argument list for formatting,
|
||||
either as the value to be formatted or as a width or specification integer,
|
||||
a new optional indexing notation <code>[</code><em>n</em><code>]</code>
|
||||
fetches argument <em>n</em> instead.
|
||||
The value of <em>n</em> is 1-indexed.
|
||||
After such an indexing operating, the next argument to be fetched by normal
|
||||
processing will be <em>n</em>+1.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
For example, the normal <code>Printf</code> call
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
fmt.Sprintf("%c %c %c\n", 'a', 'b', 'c')
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
would create the string <code>"a b c"</code>, but with indexing operations like this,
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
fmt.Sprintf("%[3]c %[1]c %c\n", 'a', 'b', 'c')
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
the result is "<code>"c a b"</code>. The <code>[3]</code> index accesses the third formatting
|
||||
argument, which is <code>'c'</code>, <code>[1]</code> accesses the first, <code>'a'</code>,
|
||||
and then the next fetch accesses the argument following that one, <code>'b'</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The motivation for this feature is programmable format statements to access
|
||||
the arguments in different order for localization, but it has other uses:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
log.Printf("trace: value %v of type %[1]T\n", expensiveFunction(a.b[c]))
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
<em>Updating</em>: The change to the syntax of format specifications
|
||||
is strictly backwards compatible, so it affects no working programs.
|
||||
</p>
|
||||
|
||||
<h3 id="text_template">The text/template and html/template packages</h3>
|
||||
|
||||
<p>
|
||||
The
|
||||
<a href="/pkg/text/template/"><code>text/template</code></a> package
|
||||
has a couple of changes in Go 1.2, both of which are also mirrored in the
|
||||
<a href="/pkg/html/template/"><code>html/template</code></a> package.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
First, there are new default functions for comparing basic types.
|
||||
The functions are listed in this table, which shows their names and
|
||||
the associated familiar comparison operator.
|
||||
</p>
|
||||
|
||||
<table cellpadding="0" summary="Template comparison functions">
|
||||
<tr>
|
||||
<th width="50"></th><th width="100">Name</th> <th width="50">Operator</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td><td><code>eq</code></td> <td><code>==</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td><td><code>ne</code></td> <td><code>!=</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td><td><code>lt</code></td> <td><code><</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td><td><code>le</code></td> <td><code><=</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td><td><code>gt</code></td> <td><code>></code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td><td><code>ge</code></td> <td><code>>=</code></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<p>
|
||||
These functions behave slightly differently from the corresponding Go operators.
|
||||
First, they operate only on basic types (<code>bool</code>, <code>int</code>,
|
||||
<code>float64</code>, <code>string</code>, etc.).
|
||||
(Go allows comparison of arrays and structs as well, under some circumstances.)
|
||||
Second, values can be compared as long as they are the same sort of value:
|
||||
any signed integer value can be compared to any other signed integer value for example. (Go
|
||||
does not permit comparing an <code>int8</code> and an <code>int16</code>).
|
||||
Finally, the <code>eq</code> function (only) allows comparison of the first
|
||||
argument with one or more following arguments. The template in this example,
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
{{"{{"}}if eq .A 1 2 3 {{"}}"}} equal {{"{{"}}else{{"}}"}} not equal {{"{{"}}end{{"}}"}}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
reports "equal" if <code>.A</code> is equal to <em>any</em> of 1, 2, or 3.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The second change is that a small addition to the grammar makes "if else if" chains easier to write.
|
||||
Instead of writing,
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
{{"{{"}}if eq .A 1{{"}}"}} X {{"{{"}}else{{"}}"}} {{"{{"}}if eq .A 2{{"}}"}} Y {{"{{"}}end{{"}}"}} {{"{{"}}end{{"}}"}}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
one can fold the second "if" into the "else" and have only one "end", like this:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
{{"{{"}}if eq .A 1{{"}}"}} X {{"{{"}}else if eq .A 2{{"}}"}} Y {{"{{"}}end{{"}}"}}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The two forms are identical in effect; the difference is just in the syntax.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<em>Updating</em>: Neither the "else if" change nor the comparison functions
|
||||
affect existing programs. Those that
|
||||
already define functions called <code>eq</code> and so on through a function
|
||||
map are unaffected because the associated function map will override the new
|
||||
default function definitions.
|
||||
</p>
|
||||
|
||||
<h3 id="new_packages">New packages</h3>
|
||||
|
||||
<p>
|
||||
There are two new packages.
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
The <a href="/pkg/encoding/"><code>encoding</code></a> package is
|
||||
<a href="#encoding">described above</a>.
|
||||
</li>
|
||||
<li>
|
||||
The <a href="/pkg/image/color/palette/"><code>image/color/palette</code></a> package
|
||||
provides standard color palettes.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="minor_library_changes">Minor changes to the library</h3>
|
||||
|
||||
<p>
|
||||
The following list summarizes a number of minor changes to the library, mostly additions.
|
||||
See the relevant package documentation for more information about each change.
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/archive/zip/"><code>archive/zip</code></a> package
|
||||
adds the
|
||||
<a href="/pkg/archive/zip/#File.DataOffset"><code>DataOffset</code></a> accessor
|
||||
to return the offset of a file's (possibly compressed) data within the archive.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/bufio/"><code>bufio</code></a> package
|
||||
adds <a href="/pkg/bufio/#Reader.Reset"><code>Reset</code></a>
|
||||
methods to <a href="/pkg/bufio/#Reader"><code>Reader</code></a> and
|
||||
<a href="/pkg/bufio/#Writer"><code>Writer</code></a>.
|
||||
These methods allow the <a href="/pkg/io/#Reader"><code>Readers</code></a>
|
||||
and <a href="/pkg/io/#Writer"><code>Writers</code></a>
|
||||
to be re-used on new input and output readers and writers, saving
|
||||
allocation overhead.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/compress/bzip2/"><code>compress/bzip2</code></a>
|
||||
can now decompress concatenated archives.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/compress/flate/"><code>compress/flate</code></a>
|
||||
package adds a <a href="/pkg/compress/flate/#Writer.Reset"><code>Reset</code></a>
|
||||
method on the <a href="/pkg/compress/flate/#Writer"><code>Writer</code></a>,
|
||||
to make it possible to reduce allocation when, for instance, constructing an
|
||||
archive to hold multiple compressed files.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/compress/gzip/"><code>compress/gzip</code></a> package's
|
||||
<a href="/pkg/compress/gzip/#Writer"><code>Writer</code></a> type adds a
|
||||
<a href="/pkg/compress/gzip/#Writer.Reset"><code>Reset</code></a>
|
||||
so it may be reused.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/compress/zlib/"><code>compress/zlib</code></a> package's
|
||||
<a href="/pkg/compress/zlib/#Writer"><code>Writer</code></a> type adds a
|
||||
<a href="/pkg/compress/zlib/#Writer.Reset"><code>Reset</code></a>
|
||||
so it may be reused.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/container/heap/"><code>container/heap</code></a> package
|
||||
adds a <a href="/pkg/container/heap/#Fix"><code>Fix</code></a>
|
||||
method to provide a more efficient way to update an item's position in the heap.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/container/list/"><code>container/list</code></a> package
|
||||
adds the <a href="/pkg/container/list/#List.MoveBefore"><code>MoveBefore</code></a>
|
||||
and
|
||||
<a href="/pkg/container/list/#List.MoveAfter"><code>MoveAfter</code></a>
|
||||
methods, which implement the obvious rearrangement.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/crypto/cipher/"><code>crypto/cipher</code></a> package
|
||||
adds the a new GCM mode (Galois Counter Mode), which is almost always
|
||||
used with AES encryption.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The
|
||||
<a href="/pkg/crypto/md5/"><code>crypto/md5</code></a> package
|
||||
adds a new <a href="/pkg/crypto/md5/#Sum"><code>Sum</code></a> function
|
||||
to simplify hashing without sacrificing performance.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
Similarly, the
|
||||
<a href="/pkg/crypto/md5/"><code>crypto/sha1</code></a> package
|
||||
adds a new <a href="/pkg/crypto/sha1/#Sum"><code>Sum</code></a> function.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
Also, the
|
||||
<a href="/pkg/crypto/sha256/"><code>crypto/sha256</code></a> package
|
||||
adds <a href="/pkg/crypto/sha256/#Sum256"><code>Sum256</code></a>
|
||||
and <a href="/pkg/crypto/sha256/#Sum224"><code>Sum224</code></a> functions.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
Finally, the <a href="/pkg/crypto/sha512/"><code>crypto/sha512</code></a> package
|
||||
adds <a href="/pkg/crypto/sha512/#Sum512"><code>Sum512</code></a> and
|
||||
<a href="/pkg/crypto/sha512/#Sum384"><code>Sum384</code></a> functions.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/crypto/x509/"><code>crypto/x509</code></a> package
|
||||
adds support for reading and writing arbitrary extensions.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/crypto/tls/"><code>crypto/tls</code></a> package adds
|
||||
support for TLS 1.1, 1.2 and AES-GCM.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/database/sql/"><code>database/sql</code></a> package adds a
|
||||
<a href="/pkg/database/sql/#DB.SetMaxOpenConns"><code>SetMaxOpenConns</code></a>
|
||||
method on <a href="/pkg/database/sql/#DB"><code>DB</code></a> to limit the
|
||||
number of open connections to the database.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/encoding/csv/"><code>encoding/csv</code></a> package
|
||||
now always allows trailing commas on fields.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/encoding/gob/"><code>encoding/gob</code></a> package
|
||||
now treats channel and function fields of structures as if they were unexported,
|
||||
even if they are not. That is, it ignores them completely. Previously they would
|
||||
trigger an error, which could cause unexpected compatibility problems if an
|
||||
embedded structure added such a field.
|
||||
The package also now supports the generic <code>BinaryMarshaler</code> and
|
||||
<code>BinaryUnmarshaler</code> interfaces of the
|
||||
<a href="/pkg/encoding/"><code>encoding</code></a> package
|
||||
described above.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/encoding/json/"><code>encoding/json</code></a> package
|
||||
now will always escape ampersands as "\u0026" when printing strings.
|
||||
It will now accept but correct invalid UTF-8 in
|
||||
<a href="/pkg/encoding/json/#Marshal"><code>Marshal</code></a>
|
||||
(such input was previously rejected).
|
||||
Finally, it now supports the generic encoding interfaces of the
|
||||
<a href="/pkg/encoding/"><code>encoding</code></a> package
|
||||
described above.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/encoding/xml/"><code>encoding/xml</code></a> package
|
||||
now allows attributes stored in pointers to be marshaled.
|
||||
It also supports the generic encoding interfaces of the
|
||||
<a href="/pkg/encoding/"><code>encoding</code></a> package
|
||||
described above through the new
|
||||
<a href="/pkg/encoding/xml/#Marshaler"><code>Marshaler</code></a>,
|
||||
<a href="/pkg/encoding/xml/#Unmarshaler"><code>Unmarshaler</code></a>,
|
||||
and related
|
||||
<a href="/pkg/encoding/xml/#MarshalerAttr"><code>MarshalerAttr</code></a> and
|
||||
<a href="/pkg/encoding/xml/#UnmarshalerAttr"><code>UnmarshalerAttr</code></a>
|
||||
interfaces.
|
||||
The package also adds a
|
||||
<a href="/pkg/encoding/xml/#Encoder.Flush"><code>Flush</code></a> method
|
||||
to the
|
||||
<a href="/pkg/encoding/xml/#Encoder"><code>Encoder</code></a>
|
||||
type for use by custom encoders. See the documentation for
|
||||
<a href="/pkg/encoding/xml/#Encoder.EncodeToken"><code>EncodeToken</code></a>
|
||||
to see how to use it.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/flag/"><code>flag</code></a> package now
|
||||
has a <a href="/pkg/flag/#Getter"><code>Getter</code></a> interface
|
||||
to allow the value of a flag to be retrieved. Due to the
|
||||
Go 1 compatibility guidelines, this method cannot be added to the existing
|
||||
<a href="/pkg/flag/#Value"><code>Value</code></a>
|
||||
interface, but all the existing standard flag types implement it.
|
||||
The package also now exports the <a href="/pkg/flag/#CommandLine"><code>CommandLine</code></a>
|
||||
flag set, which holds the flags from the command line.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/go/ast/"><code>go/ast</code></a> package's
|
||||
<a href="/pkg/go/ast/#SliceExpr"><code>SliceExpr</code></a> struct
|
||||
has a new boolean field, <code>Slice3</code>, which is set to true
|
||||
when representing a slice expression with three indices (two colons).
|
||||
The default is false, representing the usual two-index form.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/go/build/"><code>go/build</code></a> package adds
|
||||
the <code>AllTags</code> field
|
||||
to the <a href="/pkg/go/build/#Package"><code>Package</code></a> type,
|
||||
to make it easier to process build tags.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/image/draw/"><code>image/draw</code></a> package now
|
||||
exports an interface, <a href="/pkg/image/draw/#Drawer"><code>Drawer</code></a>,
|
||||
that wraps the standard <a href="/pkg/image/draw/#Draw"><code>Draw</code></a> method.
|
||||
The Porter-Duff operators now implement this interface, in effect binding an operation to
|
||||
the draw operator rather than providing it explicitly.
|
||||
Given a paletted image as its destination, the new
|
||||
<a href="/pkg/image/draw/#FloydSteinberg"><code>FloydSteinberg</code></a>
|
||||
implementation of the
|
||||
<a href="/pkg/image/draw/#Drawer"><code>Drawer</code></a>
|
||||
interface will use the Floyd-Steinberg error diffusion algorithm to draw the image.
|
||||
To create palettes suitable for such processing, the new
|
||||
<a href="/pkg/image/draw/#Quantizer"><code>Quantizer</code></a> interface
|
||||
represents implementations of quantization algorithms that choose a palette
|
||||
given a full-color image.
|
||||
There are no implementations of this interface in the library.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/image/gif/"><code>image/gif</code></a> package
|
||||
can now create GIF files using the new
|
||||
<a href="/pkg/image/gif/#Encode"><code>Encode</code></a>
|
||||
and <a href="/pkg/image/gif/#EncodeAll"><code>EncodeAll</code></a>
|
||||
functions.
|
||||
Their options argument allows specification of an image
|
||||
<a href="/pkg/image/draw/#Quantizer"><code>Quantizer</code></a> to use;
|
||||
if it is <code>nil</code>, the generated GIF will use the
|
||||
<a href="/pkg/image/color/palette/#Plan9"><code>Plan9</code></a>
|
||||
color map (palette) defined in the new
|
||||
<a href="/pkg/image/color/palette/"><code>image/color/palette</code></a> package.
|
||||
The options also specify a
|
||||
<a href="/pkg/image/draw/#Drawer"><code>Drawer</code></a>
|
||||
to use to create the output image;
|
||||
if it is <code>nil</code>, Floyd-Steinberg error diffusion is used.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/io/#Copy"><code>Copy</code></a> method of the
|
||||
<a href="/pkg/io/"><code>io</code></a> package now prioritizes its
|
||||
arguments differently.
|
||||
If one argument implements <a href="/pkg/io/#WriterTo"><code>WriterTo</code></a>
|
||||
and the other implements <a href="/pkg/io/#ReaderFrom"><code>ReaderFrom</code></a>,
|
||||
<a href="/pkg/io/#Copy"><code>Copy</code></a> will now invoke
|
||||
<a href="/pkg/io/#WriterTo"><code>WriterTo</code></a> to do the work,
|
||||
so that less intermediate buffering is required in general.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/net/"><code>net</code></a> package requires cgo by default
|
||||
because the host operating system must in general mediate network call setup.
|
||||
On some systems, though, it is possible to use the network without cgo, and useful
|
||||
to do so, for instance to avoid dynamic linking.
|
||||
The new build tag <code>netgo</code> (off by default) allows the construction of a
|
||||
<code>net</code> package in pure Go on those systems where it is possible.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/net/"><code>net</code></a> package adds a new field
|
||||
<code>DualStack</code> to the <a href="/pkg/net/#Dialer"><code>Dialer</code></a>
|
||||
struct for TCP connection setup using a dual IP stack as described in
|
||||
<a href="http://tools.ietf.org/html/rfc6555">RFC 6555</a>.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/net/http/"><code>net/http</code></a> package will no longer
|
||||
transmit cookies that are incorrect according to
|
||||
<a href="http://tools.ietf.org/html/rfc6265">RFC 6265</a>.
|
||||
It just logs an error and sends nothing.
|
||||
Also,
|
||||
the <a href="/pkg/net/http/"><code>net/http</code></a> package's
|
||||
<a href="/pkg/net/http/#ReadResponse"><code>ReadResponse</code></a>
|
||||
function now permits the <code>*Request</code> parameter to be <code>nil</code>,
|
||||
whereupon it assumes a GET request.
|
||||
Finally, an HTTP server will now serve HEAD
|
||||
requests transparently, without the need for special casing in handler code.
|
||||
While serving a HEAD request, writes to a
|
||||
<a href="/pkg/net/http/#Handler"><code>Handler</code></a>'s
|
||||
<a href="/pkg/net/http/#ResponseWriter"><code>ResponseWriter</code></a>
|
||||
are absorbed by the
|
||||
<a href="/pkg/net/http/#Server"><code>Server</code></a>
|
||||
and the client receives an empty body as required by the HTTP specification.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/os/exec/"><code>os/exec</code></a> package's
|
||||
<a href="/pkg/os/exec/#Cmd.StdinPipe"><code>Cmd.StdinPipe</code></a> method
|
||||
returns an <code>io.WriteCloser</code>, but has changed its concrete
|
||||
implementation from <code>*os.File</code> to an unexported type that embeds
|
||||
<code>*os.File</code>, and it is now safe to close the returned value.
|
||||
Before Go 1.2, there was an unavoidable race that this change fixes.
|
||||
Code that needs access to the methods of <code>*os.File</code> can use an
|
||||
interface type assertion, such as <code>wc.(interface{ Sync() error })</code>.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/runtime/"><code>runtime</code></a> package relaxes
|
||||
the constraints on finalizer functions in
|
||||
<a href="/pkg/runtime/#SetFinalizer"><code>SetFinalizer</code></a>: the
|
||||
actual argument can now be any type that is assignable to the formal type of
|
||||
the function, as is the case for any normal function call in Go.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/sort/"><code>sort</code></a> package has a new
|
||||
<a href="/pkg/sort/#Stable"><code>Stable</code></a> function that implements
|
||||
stable sorting. It is less efficient than the normal sort algorithm, however.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/strings/"><code>strings</code></a> package adds
|
||||
an <a href="/pkg/strings/#IndexByte"><code>IndexByte</code></a>
|
||||
function for consistency with the <a href="/pkg/bytes/"><code>bytes</code></a> package.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/sync/atomic/"><code>sync/atomic</code></a> package
|
||||
adds a new set of swap functions that atomically exchange the argument with the
|
||||
value stored in the pointer, returning the old value.
|
||||
The functions are
|
||||
<a href="/pkg/sync/atomic/#SwapInt32"><code>SwapInt32</code></a>,
|
||||
<a href="/pkg/sync/atomic/#SwapInt64"><code>SwapInt64</code></a>,
|
||||
<a href="/pkg/sync/atomic/#SwapUint32"><code>SwapUint32</code></a>,
|
||||
<a href="/pkg/sync/atomic/#SwapUint64"><code>SwapUint64</code></a>,
|
||||
<a href="/pkg/sync/atomic/#SwapUintptr"><code>SwapUintptr</code></a>,
|
||||
and
|
||||
<a href="/pkg/sync/atomic/#SwapPointer"><code>SwapPointer</code></a>,
|
||||
which swaps an <code>unsafe.Pointer</code>.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/syscall/"><code>syscall</code></a> package now implements
|
||||
<a href="/pkg/syscall/#Sendfile"><code>Sendfile</code></a> for Darwin.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/testing/"><code>testing</code></a> package
|
||||
now exports the <a href="/pkg/testing/#TB"><code>TB</code></a> interface.
|
||||
It records the methods in common with the
|
||||
<a href="/pkg/testing/#T"><code>T</code></a>
|
||||
and
|
||||
<a href="/pkg/testing/#B"><code>B</code></a> types,
|
||||
to make it easier to share code between tests and benchmarks.
|
||||
Also, the
|
||||
<a href="/pkg/testing/#AllocsPerRun"><code>AllocsPerRun</code></a>
|
||||
function now quantizes the return value to an integer (although it
|
||||
still has type <code>float64</code>), to round off any error caused by
|
||||
initialization and make the result more repeatable.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/text/template/"><code>text/template</code></a> package
|
||||
now automatically dereferences pointer values when evaluating the arguments
|
||||
to "escape" functions such as "html", to bring the behavior of such functions
|
||||
in agreement with that of other printing functions such as "printf".
|
||||
</li>
|
||||
|
||||
<li>
|
||||
In the <a href="/pkg/time/"><code>time</code></a> package, the
|
||||
<a href="/pkg/time/#Parse"><code>Parse</code></a> function
|
||||
and
|
||||
<a href="/pkg/time/#Time.Format"><code>Format</code></a>
|
||||
method
|
||||
now handle time zone offsets with seconds, such as in the historical
|
||||
date "1871-01-01T05:33:02+00:34:08".
|
||||
Also, pattern matching in the formats for those routines is stricter: a non-lowercase letter
|
||||
must now follow the standard words such as "Jan" and "Mon".
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/unicode/"><code>unicode</code></a> package
|
||||
adds <a href="/pkg/unicode/#In"><code>In</code></a>,
|
||||
a nicer-to-use but equivalent version of the original
|
||||
<a href="/pkg/unicode/#IsOneOf"><code>IsOneOf</code></a>,
|
||||
to see whether a character is a member of a Unicode category.
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
608
doc/go1.3.html
@@ -1,608 +0,0 @@
|
||||
<!--{
|
||||
"Title": "Go 1.3 Release Notes",
|
||||
"Path": "/doc/go1.3",
|
||||
"Template": true
|
||||
}-->
|
||||
|
||||
<h2 id="introduction">Introduction to Go 1.3</h2>
|
||||
|
||||
<p>
|
||||
The latest Go release, version 1.3, arrives six months after 1.2,
|
||||
and contains no language changes.
|
||||
It focuses primarily on implementation work, providing
|
||||
precise garbage collection,
|
||||
a major refactoring of the compiler tool chain that results in
|
||||
faster builds, especially for large projects,
|
||||
significant performance improvements across the board,
|
||||
and support for DragonFly BSD, Solaris, Plan 9 and Google's Native Client architecture (NaCl).
|
||||
It also has an important refinement to the memory model regarding synchronization.
|
||||
As always, Go 1.3 keeps the <a href="/doc/go1compat.html">promise
|
||||
of compatibility</a>,
|
||||
and almost everything
|
||||
will continue to compile and run without change when moved to 1.3.
|
||||
</p>
|
||||
|
||||
<h2 id="os">Changes to the supported operating systems and architectures</h2>
|
||||
|
||||
<h3 id="win2000">Removal of support for Windows 2000</h3>
|
||||
|
||||
<p>
|
||||
Microsoft stopped supporting Windows 2000 in 2010.
|
||||
Since it has <a href="https://codereview.appspot.com/74790043">implementation difficulties</a>
|
||||
regarding exception handling (signals in Unix terminology),
|
||||
as of Go 1.3 it is not supported by Go either.
|
||||
</p>
|
||||
|
||||
<h3 id="dragonfly">Support for DragonFly BSD</h3>
|
||||
|
||||
<p>
|
||||
Go 1.3 now includes experimental support for DragonFly BSD on the <code>amd64</code> (64-bit x86) and <code>386</code> (32-bit x86) architectures.
|
||||
It uses DragonFly BSD 3.6 or above.
|
||||
</p>
|
||||
|
||||
<h3 id="freebsd">Support for FreeBSD</h3>
|
||||
|
||||
<p>
|
||||
It was not announced at the time, but since the release of Go 1.2, support for Go on FreeBSD
|
||||
requires FreeBSD 8 or above.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
As of Go 1.3, support for Go on FreeBSD requires that the kernel be compiled with the
|
||||
<code>COMPAT_FREEBSD32</code> flag configured.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
In concert with the switch to EABI syscalls for ARM platforms, Go 1.3 will run only on FreeBSD 10.
|
||||
The x86 platforms, 386 and amd64, are unaffected.
|
||||
</p>
|
||||
|
||||
<h3 id="nacl">Support for Native Client</h3>
|
||||
|
||||
<p>
|
||||
Support for the Native Client virtual machine architecture has returned to Go with the 1.3 release.
|
||||
It runs on the 32-bit Intel architectures (<code>GOARCH=386</code>) and also on 64-bit Intel, but using
|
||||
32-bit pointers (<code>GOARCH=amd64p32</code>).
|
||||
There is not yet support for Native Client on ARM.
|
||||
Note that this is Native Client (NaCl), not Portable Native Client (PNaCl).
|
||||
Details about Native Client are <a href="https://developers.google.com/native-client/dev/">here</a>;
|
||||
how to set up the Go version is described <a href="//golang.org/wiki/NativeClient">here</a>.
|
||||
</p>
|
||||
|
||||
<h3 id="netbsd">Support for NetBSD</h3>
|
||||
|
||||
<p>
|
||||
As of Go 1.3, support for Go on NetBSD requires NetBSD 6.0 or above.
|
||||
</p>
|
||||
|
||||
<h3 id="openbsd">Support for OpenBSD</h3>
|
||||
|
||||
<p>
|
||||
As of Go 1.3, support for Go on OpenBSD requires OpenBSD 5.5 or above.
|
||||
</p>
|
||||
|
||||
<h3 id="plan9">Support for Plan 9</h3>
|
||||
|
||||
<p>
|
||||
Go 1.3 now includes experimental support for Plan 9 on the <code>386</code> (32-bit x86) architecture.
|
||||
It requires the <code>Tsemacquire</code> syscall, which has been in Plan 9 since June, 2012.
|
||||
</p>
|
||||
|
||||
<h3 id="solaris">Support for Solaris</h3>
|
||||
|
||||
<p>
|
||||
Go 1.3 now includes experimental support for Solaris on the <code>amd64</code> (64-bit x86) architecture.
|
||||
It requires illumos, Solaris 11 or above.
|
||||
</p>
|
||||
|
||||
<h2 id="memory">Changes to the memory model</h2>
|
||||
|
||||
<p>
|
||||
The Go 1.3 memory model <a href="https://codereview.appspot.com/75130045">adds a new rule</a>
|
||||
concerning sending and receiving on buffered channels,
|
||||
to make explicit that a buffered channel can be used as a simple
|
||||
semaphore, using a send into the
|
||||
channel to acquire and a receive from the channel to release.
|
||||
This is not a language change, just a clarification about an expected property of communication.
|
||||
</p>
|
||||
|
||||
<h2 id="impl">Changes to the implementations and tools</h2>
|
||||
|
||||
<h3 id="stacks">Stack</h3>
|
||||
|
||||
<p>
|
||||
Go 1.3 has changed the implementation of goroutine stacks away from the old,
|
||||
"segmented" model to a contiguous model.
|
||||
When a goroutine needs more stack
|
||||
than is available, its stack is transferred to a larger single block of memory.
|
||||
The overhead of this transfer operation amortizes well and eliminates the old "hot spot"
|
||||
problem when a calculation repeatedly steps across a segment boundary.
|
||||
Details including performance numbers are in this
|
||||
<a href="//golang.org/s/contigstacks">design document</a>.
|
||||
</p>
|
||||
|
||||
<h3 id="garbage_collector">Changes to the garbage collector</h3>
|
||||
|
||||
<p>
|
||||
For a while now, the garbage collector has been <em>precise</em> when examining
|
||||
values in the heap; the Go 1.3 release adds equivalent precision to values on the stack.
|
||||
This means that a non-pointer Go value such as an integer will never be mistaken for a
|
||||
pointer and prevent unused memory from being reclaimed.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Starting with Go 1.3, the runtime assumes that values with pointer type
|
||||
contain pointers and other values do not.
|
||||
This assumption is fundamental to the precise behavior of both stack expansion
|
||||
and garbage collection.
|
||||
Programs that use <a href="/pkg/unsafe/">package unsafe</a>
|
||||
to store integers in pointer-typed values are illegal and will crash if the runtime detects the behavior.
|
||||
Programs that use <a href="/pkg/unsafe/">package unsafe</a> to store pointers
|
||||
in integer-typed values are also illegal but more difficult to diagnose during execution.
|
||||
Because the pointers are hidden from the runtime, a stack expansion or garbage collection
|
||||
may reclaim the memory they point at, creating
|
||||
<a href="//en.wikipedia.org/wiki/Dangling_pointer">dangling pointers</a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<em>Updating</em>: Code that uses <code>unsafe.Pointer</code> to convert
|
||||
an integer-typed value held in memory into a pointer is illegal and must be rewritten.
|
||||
Such code can be identified by <code>go vet</code>.
|
||||
</p>
|
||||
|
||||
<h3 id="map">Map iteration</h3>
|
||||
|
||||
<p>
|
||||
Iterations over small maps no longer happen in a consistent order.
|
||||
Go 1 defines that “<a href="//golang.org/ref/spec#For_statements">The iteration order over maps
|
||||
is not specified and is not guaranteed to be the same from one iteration to the next.</a>”
|
||||
To keep code from depending on map iteration order,
|
||||
Go 1.0 started each map iteration at a random index in the map.
|
||||
A new map implementation introduced in Go 1.1 neglected to randomize
|
||||
iteration for maps with eight or fewer entries, although the iteration order
|
||||
can still vary from system to system.
|
||||
This has allowed people to write Go 1.1 and Go 1.2 programs that
|
||||
depend on small map iteration order and therefore only work reliably on certain systems.
|
||||
Go 1.3 reintroduces random iteration for small maps in order to flush out these bugs.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<em>Updating</em>: If code assumes a fixed iteration order for small maps,
|
||||
it will break and must be rewritten not to make that assumption.
|
||||
Because only small maps are affected, the problem arises most often in tests.
|
||||
</p>
|
||||
|
||||
<h3 id="liblink">The linker</h3>
|
||||
|
||||
<p>
|
||||
As part of the general <a href="//golang.org/s/go13linker">overhaul</a> to
|
||||
the Go linker, the compilers and linkers have been refactored.
|
||||
The linker is still a C program, but now the instruction selection phase that
|
||||
was part of the linker has been moved to the compiler through the creation of a new
|
||||
library called <code>liblink</code>.
|
||||
By doing instruction selection only once, when the package is first compiled,
|
||||
this can speed up compilation of large projects significantly.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<em>Updating</em>: Although this is a major internal change, it should have no
|
||||
effect on programs.
|
||||
</p>
|
||||
|
||||
<h3 id="gccgo">Status of gccgo</h3>
|
||||
|
||||
<p>
|
||||
GCC release 4.9 will contain the Go 1.2 (not 1.3) version of gccgo.
|
||||
The release schedules for the GCC and Go projects do not coincide,
|
||||
which means that 1.3 will be available in the development branch but
|
||||
that the next GCC release, 4.10, will likely have the Go 1.4 version of gccgo.
|
||||
</p>
|
||||
|
||||
<h3 id="gocmd">Changes to the go command</h3>
|
||||
|
||||
<p>
|
||||
The <a href="/cmd/go/"><code>cmd/go</code></a> command has several new
|
||||
features.
|
||||
The <a href="/cmd/go/"><code>go run</code></a> and
|
||||
<a href="/cmd/go/"><code>go test</code></a> subcommands
|
||||
support a new <code>-exec</code> option to specify an alternate
|
||||
way to run the resulting binary.
|
||||
Its immediate purpose is to support NaCl.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The test coverage support of the <a href="/cmd/go/"><code>go test</code></a>
|
||||
subcommand now automatically sets the coverage mode to <code>-atomic</code>
|
||||
when the race detector is enabled, to eliminate false reports about unsafe
|
||||
access to coverage counters.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The <a href="/cmd/go/"><code>go test</code></a> subcommand
|
||||
now always builds the package, even if it has no test files.
|
||||
Previously, it would do nothing if no test files were present.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The <a href="/cmd/go/"><code>go build</code></a> subcommand
|
||||
supports a new <code>-i</code> option to install dependencies
|
||||
of the specified target, but not the target itself.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Cross compiling with <a href="/cmd/cgo/"><code>cgo</code></a> enabled
|
||||
is now supported.
|
||||
The CC_FOR_TARGET and CXX_FOR_TARGET environment
|
||||
variables are used when running all.bash to specify the cross compilers
|
||||
for C and C++ code, respectively.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Finally, the go command now supports packages that import Objective-C
|
||||
files (suffixed <code>.m</code>) through cgo.
|
||||
</p>
|
||||
|
||||
<h3 id="cgo">Changes to cgo</h3>
|
||||
|
||||
<p>
|
||||
The <a href="/cmd/cgo/"><code>cmd/cgo</code></a> command,
|
||||
which processes <code>import "C"</code> declarations in Go packages,
|
||||
has corrected a serious bug that may cause some packages to stop compiling.
|
||||
Previously, all pointers to incomplete struct types translated to the Go type <code>*[0]byte</code>,
|
||||
with the effect that the Go compiler could not diagnose passing one kind of struct pointer
|
||||
to a function expecting another.
|
||||
Go 1.3 corrects this mistake by translating each different
|
||||
incomplete struct to a different named type.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Given the C declaration <code>typedef struct S T</code> for an incomplete <code>struct S</code>,
|
||||
some Go code used this bug to refer to the types <code>C.struct_S</code> and <code>C.T</code> interchangeably.
|
||||
Cgo now explicitly allows this use, even for completed struct types.
|
||||
However, some Go code also used this bug to pass (for example) a <code>*C.FILE</code>
|
||||
from one package to another.
|
||||
This is not legal and no longer works: in general Go packages
|
||||
should avoid exposing C types and names in their APIs.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<em>Updating</em>: Code confusing pointers to incomplete types or
|
||||
passing them across package boundaries will no longer compile
|
||||
and must be rewritten.
|
||||
If the conversion is correct and must be preserved,
|
||||
use an explicit conversion via <a href="/pkg/unsafe/#Pointer"><code>unsafe.Pointer</code></a>.
|
||||
</p>
|
||||
|
||||
<h3 id="swig">SWIG 3.0 required for programs that use SWIG</h3>
|
||||
|
||||
<p>
|
||||
For Go programs that use SWIG, SWIG version 3.0 is now required.
|
||||
The <a href="/cmd/go"><code>cmd/go</code></a> command will now link the
|
||||
SWIG generated object files directly into the binary, rather than
|
||||
building and linking with a shared library.
|
||||
</p>
|
||||
|
||||
<h3 id="gc_flag">Command-line flag parsing</h3>
|
||||
|
||||
<p>
|
||||
In the gc tool chain, the assemblers now use the
|
||||
same command-line flag parsing rules as the Go flag package, a departure
|
||||
from the traditional Unix flag parsing.
|
||||
This may affect scripts that invoke the tool directly.
|
||||
For example,
|
||||
<code>go tool 6a -SDfoo</code> must now be written
|
||||
<code>go tool 6a -S -D foo</code>.
|
||||
(The same change was made to the compilers and linkers in <a href="/doc/go1.1#gc_flag">Go 1.1</a>.)
|
||||
</p>
|
||||
|
||||
<h3 id="godoc">Changes to godoc</h3>
|
||||
<p>
|
||||
When invoked with the <code>-analysis</code> flag,
|
||||
<a href="//godoc.org/code.google.com/p/go.tools/cmd/godoc">godoc</a>
|
||||
now performs sophisticated <a href="/lib/godoc/analysis/help.html">static
|
||||
analysis</a> of the code it indexes.
|
||||
The results of analysis are presented in both the source view and the
|
||||
package documentation view, and include the call graph of each package
|
||||
and the relationships between
|
||||
definitions and references,
|
||||
types and their methods,
|
||||
interfaces and their implementations,
|
||||
send and receive operations on channels,
|
||||
functions and their callers, and
|
||||
call sites and their callees.
|
||||
</p>
|
||||
|
||||
<h3 id="misc">Miscellany</h3>
|
||||
|
||||
<p>
|
||||
The program <code>misc/benchcmp</code> that compares
|
||||
performance across benchmarking runs has been rewritten.
|
||||
Once a shell and awk script in the main repository, it is now a Go program in the <code>go.tools</code> repo.
|
||||
Documentation is <a href="//godoc.org/code.google.com/p/go.tools/cmd/benchcmp">here</a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
For the few of us that build Go distributions, the tool <code>misc/dist</code> has been
|
||||
moved and renamed; it now lives in <code>misc/makerelease</code>, still in the main repository.
|
||||
</p>
|
||||
|
||||
<h2 id="performance">Performance</h2>
|
||||
|
||||
<p>
|
||||
The performance of Go binaries for this release has improved in many cases due to changes
|
||||
in the runtime and garbage collection, plus some changes to libraries.
|
||||
Significant instances include:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
The runtime handles defers more efficiently, reducing the memory footprint by about two kilobytes
|
||||
per goroutine that calls defer.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The garbage collector has been sped up, using a concurrent sweep algorithm,
|
||||
better parallelization, and larger pages.
|
||||
The cumulative effect can be a 50-70% reduction in collector pause time.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The race detector (see <a href="/doc/articles/race_detector.html">this guide</a>)
|
||||
is now about 40% faster.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The regular expression package <a href="/pkg/regexp/"><code>regexp</code></a>
|
||||
is now significantly faster for certain simple expressions due to the implementation of
|
||||
a second, one-pass execution engine.
|
||||
The choice of which engine to use is automatic;
|
||||
the details are hidden from the user.
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
Also, the runtime now includes in stack dumps how long a goroutine has been blocked,
|
||||
which can be useful information when debugging deadlocks or performance issues.
|
||||
</p>
|
||||
|
||||
<h2 id="library">Changes to the standard library</h2>
|
||||
|
||||
<h3 id="new_packages">New packages</h3>
|
||||
|
||||
<p>
|
||||
A new package <a href="/pkg/debug/plan9obj/"><code>debug/plan9obj</code></a> was added to the standard library.
|
||||
It implements access to Plan 9 <a href="http://plan9.bell-labs.com/magic/man2html/6/a.out">a.out</a> object files.
|
||||
</p>
|
||||
|
||||
<h3 id="major_library_changes">Major changes to the library</h3>
|
||||
|
||||
<p>
|
||||
A previous bug in <a href="/pkg/crypto/tls/"><code>crypto/tls</code></a>
|
||||
made it possible to skip verification in TLS inadvertently.
|
||||
In Go 1.3, the bug is fixed: one must specify either ServerName or
|
||||
InsecureSkipVerify, and if ServerName is specified it is enforced.
|
||||
This may break existing code that incorrectly depended on insecure
|
||||
behavior.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
There is an important new type added to the standard library: <a href="/pkg/sync/#Pool"><code>sync.Pool</code></a>.
|
||||
It provides an efficient mechanism for implementing certain types of caches whose memory
|
||||
can be reclaimed automatically by the system.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The <a href="/pkg/testing/"><code>testing</code></a> package's benchmarking helper,
|
||||
<a href="/pkg/testing/#B"><code>B</code></a>, now has a
|
||||
<a href="/pkg/testing/#B.RunParallel"><code>RunParallel</code></a> method
|
||||
to make it easier to run benchmarks that exercise multiple CPUs.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<em>Updating</em>: The crypto/tls fix may break existing code, but such
|
||||
code was erroneous and should be updated.
|
||||
</p>
|
||||
|
||||
<h3 id="minor_library_changes">Minor changes to the library</h3>
|
||||
|
||||
<p>
|
||||
The following list summarizes a number of minor changes to the library, mostly additions.
|
||||
See the relevant package documentation for more information about each change.
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
|
||||
<li> In the <a href="/pkg/crypto/tls/"><code>crypto/tls</code></a> package,
|
||||
a new <a href="/pkg/crypto/tls/#DialWithDialer"><code>DialWithDialer</code></a>
|
||||
function lets one establish a TLS connection using an existing dialer, making it easier
|
||||
to control dial options such as timeouts.
|
||||
The package also now reports the TLS version used by the connection in the
|
||||
<a href="/pkg/crypto/tls/#ConnectionState"><code>ConnectionState</code></a>
|
||||
struct.
|
||||
</li>
|
||||
|
||||
<li> The <a href="/pkg/crypto/x509/#CreateCertificate"><code>CreateCertificate</code></a>
|
||||
function of the <a href="/pkg/crypto/tls/"><code>crypto/tls</code></a> package
|
||||
now supports parsing (and elsewhere, serialization) of PKCS #10 certificate
|
||||
signature requests.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The formatted print functions of the <code>fmt</code> package now define <code>%F</code>
|
||||
as a synonym for <code>%f</code> when printing floating-point values.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/math/big/"><code>math/big</code></a> package's
|
||||
<a href="/pkg/math/big/#Int"><code>Int</code></a> and
|
||||
<a href="/pkg/math/big/#Rat"><code>Rat</code></a> types
|
||||
now implement
|
||||
<a href="/pkg/encoding/#TextMarshaler"><code>encoding.TextMarshaler</code></a> and
|
||||
<a href="/pkg/encoding/#TextUnmarshaler"><code>encoding.TextUnmarshaler</code></a>.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The complex power function, <a href="/pkg/math/cmplx/#Pow"><code>Pow</code></a>,
|
||||
now specifies the behavior when the first argument is zero.
|
||||
It was undefined before.
|
||||
The details are in the <a href="/pkg/math/cmplx/#Pow">documentation for the function</a>.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/net/http/"><code>net/http</code></a> package now exposes the
|
||||
properties of a TLS connection used to make a client request in the new
|
||||
<a href="/pkg/net/http/#Response"><code>Response.TLS</code></a> field.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/net/http/"><code>net/http</code></a> package now
|
||||
allows setting an optional server error logger
|
||||
with <a href="/pkg/net/http/#Server"><code>Server.ErrorLog</code></a>.
|
||||
The default is still that all errors go to stderr.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/net/http/"><code>net/http</code></a> package now
|
||||
supports disabling HTTP keep-alive connections on the server
|
||||
with <a href="/pkg/net/http/#Server.SetKeepAlivesEnabled"><code>Server.SetKeepAlivesEnabled</code></a>.
|
||||
The default continues to be that the server does keep-alive (reuses
|
||||
connections for multiple requests) by default.
|
||||
Only resource-constrained servers or those in the process of graceful
|
||||
shutdown will want to disable them.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/net/http/"><code>net/http</code></a> package adds an optional
|
||||
<a href="/pkg/net/http/#Transport"><code>Transport.TLSHandshakeTimeout</code></a>
|
||||
setting to cap the amount of time HTTP client requests will wait for
|
||||
TLS handshakes to complete.
|
||||
It's now also set by default
|
||||
on <a href="/pkg/net/http#DefaultTransport"><code>DefaultTransport</code></a>.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/net/http/"><code>net/http</code></a> package's
|
||||
<a href="/pkg/net/http/#DefaultTransport"><code>DefaultTransport</code></a>,
|
||||
used by the HTTP client code, now
|
||||
enables <a href="http://en.wikipedia.org/wiki/Keepalive#TCP_keepalive">TCP
|
||||
keep-alives</a> by default.
|
||||
Other <a href="/pkg/net/http/#Transport"><code>Transport</code></a>
|
||||
values with a nil <code>Dial</code> field continue to function the same
|
||||
as before: no TCP keep-alives are used.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/net/http/"><code>net/http</code></a> package
|
||||
now enables <a href="http://en.wikipedia.org/wiki/Keepalive#TCP_keepalive">TCP
|
||||
keep-alives</a> for incoming server requests when
|
||||
<a href="/pkg/net/http/#ListenAndServe"><code>ListenAndServe</code></a>
|
||||
or
|
||||
<a href="/pkg/net/http/#ListenAndServeTLS"><code>ListenAndServeTLS</code></a>
|
||||
are used.
|
||||
When a server is started otherwise, TCP keep-alives are not enabled.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/net/http/"><code>net/http</code></a> package now
|
||||
provides an
|
||||
optional <a href="/pkg/net/http/#Server"><code>Server.ConnState</code></a>
|
||||
callback to hook various phases of a server connection's lifecycle
|
||||
(see <a href="/pkg/net/http/#ConnState"><code>ConnState</code></a>).
|
||||
This can be used to implement rate limiting or graceful shutdown.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/net/http/"><code>net/http</code></a> package's HTTP
|
||||
client now has an
|
||||
optional <a href="/pkg/net/http/#Client"><code>Client.Timeout</code></a>
|
||||
field to specify an end-to-end timeout on requests made using the
|
||||
client.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/net/http/"><code>net/http</code></a> package's
|
||||
<a href="/pkg/net/http/#Request.ParseMultipartForm"><code>Request.ParseMultipartForm</code></a>
|
||||
method will now return an error if the body's <code>Content-Type</code>
|
||||
is not <code>mutipart/form-data</code>.
|
||||
Prior to Go 1.3 it would silently fail and return <code>nil</code>.
|
||||
Code that relies on the previous behavior should be updated.
|
||||
</li>
|
||||
|
||||
<li> In the <a href="/pkg/net/"><code>net</code></a> package,
|
||||
the <a href="/pkg/net/#Dialer"><code>Dialer</code></a> struct now
|
||||
has a <code>KeepAlive</code> option to specify a keep-alive period for the connection.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/net/http/"><code>net/http</code></a> package's
|
||||
<a href="/pkg/net/http/#Transport"><code>Transport</code></a>
|
||||
now closes <a href="/pkg/net/http/#Request"><code>Request.Body</code></a>
|
||||
consistently, even on error.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/os/exec/"><code>os/exec</code></a> package now implements
|
||||
what the documentation has always said with regard to relative paths for the binary.
|
||||
In particular, it only calls <a href="/pkg/os/exec/#LookPath"><code>LookPath</code></a>
|
||||
when the binary's file name contains no path separators.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/reflect/#Value.SetMapIndex"><code>SetMapIndex</code></a>
|
||||
function in the <a href="/pkg/reflect/"><code>reflect</code></a> package
|
||||
no longer panics when deleting from a <code>nil</code> map.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
If the main goroutine calls
|
||||
<a href="/pkg/runtime/#Goexit"><code>runtime.Goexit</code></a>
|
||||
and all other goroutines finish execution, the program now always crashes,
|
||||
reporting a detected deadlock.
|
||||
Earlier versions of Go handled this situation inconsistently: most instances
|
||||
were reported as deadlocks, but some trivial cases exited cleanly instead.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The runtime/debug package now has a new function
|
||||
<a href="/pkg/runtime/debug/#WriteHeapDump"><code>debug.WriteHeapDump</code></a>
|
||||
that writes out a description of the heap.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/strconv/#CanBackquote"><code>CanBackquote</code></a>
|
||||
function in the <a href="/pkg/strconv/"><code>strconv</code></a> package
|
||||
now considers the <code>DEL</code> character, <code>U+007F</code>, to be
|
||||
non-printing.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/syscall/"><code>syscall</code></a> package now provides
|
||||
<a href="/pkg/syscall/#SendmsgN"><code>SendmsgN</code></a>
|
||||
as an alternate version of
|
||||
<a href="/pkg/syscall/#Sendmsg"><code>Sendmsg</code></a>
|
||||
that returns the number of bytes written.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
On Windows, the <a href="/pkg/syscall/"><code>syscall</code></a> package now
|
||||
supports the cdecl calling convention through the addition of a new function
|
||||
<a href="/pkg/syscall/#NewCallbackCDecl"><code>NewCallbackCDecl</code></a>
|
||||
alongside the existing function
|
||||
<a href="/pkg/syscall/#NewCallback"><code>NewCallback</code></a>.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/testing/"><code>testing</code></a> package now
|
||||
diagnoses tests that call <code>panic(nil)</code>, which are almost always erroneous.
|
||||
Also, tests now write profiles (if invoked with profiling flags) even on failure.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/unicode/"><code>unicode</code></a> package and associated
|
||||
support throughout the system has been upgraded from
|
||||
Unicode 6.2.0 to <a href="http://www.unicode.org/versions/Unicode6.3.0/">Unicode 6.3.0</a>.
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
818
doc/go1.4.html
@@ -1,818 +0,0 @@
|
||||
<!--{
|
||||
"Title": "Go 1.4 Release Notes",
|
||||
"Path": "/doc/go1.4",
|
||||
"Template": true
|
||||
}-->
|
||||
|
||||
<h2 id="introduction">Introduction to Go 1.4</h2>
|
||||
|
||||
<p>
|
||||
The latest Go release, version 1.4, arrives as scheduled six months after 1.3
|
||||
and contains only one tiny language change,
|
||||
a possibly breaking change to the compiler,
|
||||
a backwards-compatible simple form of <code>for</code>-<code>range</code> loop.
|
||||
The release focuses primarily on implementation work, improving the garbage collector
|
||||
and preparing the ground for a fully concurrent collector to be rolled out in the
|
||||
next few releases.
|
||||
Stacks are now contiguous, reallocated when necessary rather than linking on new
|
||||
"segments";
|
||||
this release therefore eliminates the notorious "hot stack split" problem.
|
||||
There are some new tools available including support in the <code>go</code> command
|
||||
for build-time source code generation.
|
||||
The release also adds support for ARM processors on Android and Native Client (NaCl)
|
||||
and AMD64 on Plan 9.
|
||||
As always, Go 1.4 keeps the <a href="/doc/go1compat.html">promise
|
||||
of compatibility</a>,
|
||||
and almost everything
|
||||
will continue to compile and run without change when moved to 1.4.
|
||||
</p>
|
||||
|
||||
<h2 id="language">Changes to the language</h2>
|
||||
|
||||
<h3 id="forrange">For-range loops</h3>
|
||||
<p>
|
||||
Up until Go 1.3, <code>for</code>-<code>range</code> loop had two forms
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
for k, v := range x {
|
||||
...
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
and
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
for k := range x {
|
||||
...
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
If one was not interested in the loop values, only the iteration itself, it was still
|
||||
necessary to mention a variable (probably the <a href="/ref/spec#Blank_identifier">blank identifier</a>, as in
|
||||
<code>for</code> <code>_</code> <code>=</code> <code>range</code> <code>x</code>), because
|
||||
the form
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
for range x {
|
||||
...
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
was not syntactically permitted.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
This situation seemed awkward, so as of Go 1.4 the variable-free form is now legal.
|
||||
The pattern arises rarely but the code can be cleaner when it does.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<em>Updating</em>: The change is strictly backwards compatible to existing Go
|
||||
programs, but tools that analyze Go parse trees may need to be modified to accept
|
||||
this new form as the
|
||||
<code>Key</code> field of <a href="/pkg/go/ast/#RangeStmt"><code>RangeStmt</code></a>
|
||||
may now be <code>nil</code>.
|
||||
</p>
|
||||
|
||||
<h3 id="methodonpointertopointer">Method calls on **T</h3>
|
||||
|
||||
<p>
|
||||
Given these declarations,
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
type T int
|
||||
func (T) M() {}
|
||||
var x **T
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
both <code>gc</code> and <code>gccgo</code> accepted the method call
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
x.M()
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
which is a double dereference of the pointer-to-pointer <code>x</code>.
|
||||
The Go specification allows a single dereference to be inserted automatically,
|
||||
but not two, so this call is erroneous according to the language definition.
|
||||
It has therefore been disallowed in Go 1.4, which is a breaking change,
|
||||
although very few programs will be affected.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<em>Updating</em>: Code that depends on the old, erroneous behavior will no longer
|
||||
compile but is easy to fix by adding an explicit dereference.
|
||||
</p>
|
||||
|
||||
<h2 id="os">Changes to the supported operating systems and architectures</h2>
|
||||
|
||||
<h3 id="android">Android</h3>
|
||||
|
||||
<p>
|
||||
Go 1.4 can build binaries for ARM processors running the Android operating system.
|
||||
It can also build a <code>.so</code> library that can be loaded by an Android application
|
||||
using the supporting packages in the <a href="http://code.google.com/p/go.mobile">go.mobile</a> repository.
|
||||
A brief description of the plans for this experimental port are available
|
||||
<a href="/s/go14android">here</a>.
|
||||
</p>
|
||||
|
||||
<h3 id="naclarm">NaCl on ARM</h3>
|
||||
|
||||
<p>
|
||||
The previous release introduced Native Client (NaCl) support for the 32-bit x86
|
||||
(<code>GOARCH=386</code>)
|
||||
and 64-bit x86 using 32-bit pointers (GOARCH=amd64p32).
|
||||
The 1.4 release adds NaCl support for ARM (GOARCH=arm).
|
||||
</p>
|
||||
|
||||
<h3 id="plan9amd64">Plan9 on AMD64</h3>
|
||||
|
||||
<p>
|
||||
This release adds support for the Plan 9 operating system on AMD64 processors,
|
||||
provided the kernel supports the <code>nsec</code> system call and uses 4K pages.
|
||||
</p>
|
||||
|
||||
<h2 id="compatibility">Changes to the compatibility guidelines</h2>
|
||||
|
||||
<p>
|
||||
The <a href="/pkg/unsafe/"><code>unsafe</code></a> package allows one
|
||||
to defeat Go's type system by exploiting internal details of the implementation
|
||||
or machine representation of data.
|
||||
It was never explicitly specified what use of <code>unsafe</code> meant
|
||||
with respect to compatibility as specified in the
|
||||
<a href="go1compat.html">Go compatibility guidelines</a>.
|
||||
The answer, of course, is that we can make no promise of compatibility
|
||||
for code that does unsafe things.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
We have clarified this situation in the documentation included in the release.
|
||||
The <a href="go1compat.html">Go compatibility guidelines</a> and the
|
||||
docs for the <a href="/pkg/unsafe/"><code>unsafe</code></a> package
|
||||
are now explicit that unsafe code is not guaranteed to remain compatible.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<em>Updating</em>: Nothing technical has changed; this is just a clarification
|
||||
of the documentation.
|
||||
</p>
|
||||
|
||||
|
||||
<h2 id="impl">Changes to the implementations and tools</h2>
|
||||
|
||||
<h3 id="runtime">Changes to the runtime</h3>
|
||||
|
||||
<p>
|
||||
Up to Go 1.4, the runtime (garbage collector, concurrency support, interface management,
|
||||
maps, slices, strings, ...) was mostly written in C, with some assembler support.
|
||||
In 1.4, much of the code has been translated to Go so that the garbage collector can scan
|
||||
the stacks of programs in the runtime and get accurate information about what variables
|
||||
are active.
|
||||
This change was large but should have no semantic effect on programs.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
This rewrite allows the garbage collector in 1.4 to be fully precise,
|
||||
meaning that it is aware of the location of all active pointers in the program.
|
||||
This means the heap will be smaller as there will be no false positives keeping non-pointers alive.
|
||||
Other related changes also reduce the heap size, which is smaller by 10%-30% overall
|
||||
relative to the previous release.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
A consequence is that stacks are no longer segmented, eliminating the "hot split" problem.
|
||||
When a stack limit is reached, a new, larger stack is allocated, all active frames for
|
||||
the goroutine are copied there, and any pointers into the stack are updated.
|
||||
Performance can be noticeably better in some cases and is always more predictable.
|
||||
Details are available in <a href="/s/contigstacks">the design document</a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The use of contiguous stacks means that stacks can start smaller without triggering performance issues,
|
||||
so the default starting size for a goroutine's stack in 1.4 has been reduced to 2048 bytes from 8192 bytes.
|
||||
TODO: It may be bumped to 4096 for the release.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
As preparation for the concurrent garbage collector scheduled for the 1.5 release,
|
||||
writes to pointer values in the heap are now done by a function call,
|
||||
called a write barrier, rather than directly from the function updating the value.
|
||||
In this next release, this will permit the garbage collector to mediate writes to the heap while it is running.
|
||||
This change has no semantic effect on programs in 1.4, but was
|
||||
included in the release to test the compiler and the resulting performance.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The implementation of interface values has been modified.
|
||||
In earlier releases, the interface contained a word that was either a pointer or a one-word
|
||||
scalar value, depending on the type of the concrete object stored.
|
||||
This implementation was problematical for the garbage collector,
|
||||
so as of 1.4 interface values always hold a pointer.
|
||||
In running programs, most interface values were pointers anyway,
|
||||
so the effect is minimal, but programs that store integers (for example) in
|
||||
interfaces will see more allocations.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
As of Go 1.3, the runtime crashes if it finds a memory word that should contain
|
||||
a valid pointer but instead contains an obviously invalid pointer (for example, the value 3).
|
||||
Programs that store integers in pointer values may run afoul of this check and crash.
|
||||
In Go 1.4, setting the <a href="/pkg/runtime/"><code>GODEBUG</code></a> variable
|
||||
<code>invalidptr=0</code> disables
|
||||
the crash as a workaround, but we cannot guarantee that future releases will be
|
||||
able to avoid the crash; the correct fix is to rewrite code not to alias integers and pointers.
|
||||
</p>
|
||||
|
||||
<h3 id="asm">Assembly</h3>
|
||||
|
||||
<p>
|
||||
The language accepted by the assemblers <code>cmd/5a</code>, <code>cmd/6a</code>
|
||||
and <code>cmd/8a</code> has had several changes,
|
||||
mostly to make it easier to deliver type information to the runtime.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
First, the <code>textflag.h</code> file that defines flags for <code>TEXT</code> directives
|
||||
has been copied from the linker source directory to a standard location so it can be
|
||||
included with the simple directive
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
#include "textflag.h"
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The more important changes are in how assembler source can define the necessary
|
||||
type information.
|
||||
For most programs it will suffice to move data
|
||||
definitions (<code>DATA</code> and <code>GLOBL</code> directives)
|
||||
out of assembly into Go files
|
||||
and to write a Go declaration for each assembly function.
|
||||
The <a href="/doc/asm#runtime">assembly document</a> describes what to do.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<em>Updating</em>:
|
||||
Assembly files that include <code>textflag.h</code> from its old
|
||||
location will still work, but should be updated.
|
||||
For the type information, most assembly routines will need no change,
|
||||
but all should be examined.
|
||||
Assembly source files that define data,
|
||||
functions with non-empty stack frames, or functions that return pointers
|
||||
need particular attention.
|
||||
A description of the necessary (but simple) changes
|
||||
is in the <a href="/doc/asm#runtime">assembly document</a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
More information about these changes is in the <a href="/doc/asm">assembly document</a>.
|
||||
</p>
|
||||
|
||||
<h3 id="gccgo">Status of gccgo</h3>
|
||||
|
||||
<p>
|
||||
The release schedules for the GCC and Go projects do not coincide.
|
||||
GCC release 4.9 contains the Go 1.2 version of gccgo.
|
||||
The next release, GCC 5, will likely have the Go 1.4 version of gccgo.
|
||||
</p>
|
||||
|
||||
<h3 id="internalpackages">Internal packages</h3>
|
||||
|
||||
<p>
|
||||
Go's package system makes it easy to structure programs into components with clean boundaries,
|
||||
but there are only two forms of access: local (unexported) and global (exported).
|
||||
Sometimes one wishes to have components that are not exported,
|
||||
for instance to avoid acquiring clients of interfaces to code that is part of a public repository
|
||||
but not intended for use outside the program to which it belongs.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The Go language does not have the power to enforce this distinction, but as of Go 1.4 the
|
||||
<a href="/cmd/go/"><code>go</code></a> command introduces
|
||||
a mechanism to define "internal" packages that may not be imported by packages outside
|
||||
the source subtree in which they reside.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
To create such a package, place it in a directory named <code>internal</code> or in a subdirectory of a directory
|
||||
named internal.
|
||||
When the <code>go</code> command sees an import of a package with <code>internal</code> in its path,
|
||||
it verifies that the package doing the import
|
||||
is within the tree rooted at the parent of the <code>internal</code> directory.
|
||||
For example, a package <code>.../a/b/c/internal/d/e/f</code>
|
||||
can be imported only by code in the directory tree rooted at <code>.../a/b/c</code>.
|
||||
It cannot be imported by code in <code>.../a/b/g</code> or in any other repository.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
For Go 1.4, the internal package mechanism is enforced for the main Go repository;
|
||||
from 1.5 and onward it will be enforced for any repository.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Full details of the mechanism are in
|
||||
<a href="http://golang.org/s/go14internal">the design document</a>.
|
||||
</p>
|
||||
|
||||
<h3 id="canonicalimports">Canonical import paths</h3>
|
||||
|
||||
<p>
|
||||
Code often lives in repositories hosted by public services such as <code>github.com</code>,
|
||||
meaning that the import paths for packages begin with the name of the hosting service,
|
||||
<code>github.com/rsc/pdf</code> for example.
|
||||
One can use
|
||||
<a href="/cmd/go/#hdr-Remote_import_paths">an existing mechanism</a>
|
||||
to provide a "custom" or "vanity" import path such as
|
||||
<code>rsc.io/pdf</code>, but
|
||||
that creates two valid import paths for the package.
|
||||
That is a problem: one may inadvertently import the package through the two
|
||||
distinct paths in a single program, which is wasteful;
|
||||
miss an update to a package because the path being used is not recognized to be
|
||||
out of date;
|
||||
or break clients using the old path by moving the package to a different hosting service.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Go 1.4 introduces an annotation for package clauses in Go source that identify a canonical
|
||||
import path for the package.
|
||||
If an import is attempted using a path that is not canonical,
|
||||
the <a href="/cmd/go/"><code>go</code></a> command
|
||||
will refuse to compile the importing package.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The syntax is simple: put an identifying comment on the package line.
|
||||
For our example, the package clause would read:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
package pdf // import "rsc.io/pdf"
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
With this in place,
|
||||
the <code>go</code> command will
|
||||
refuse to compile a package that imports <code>github.com/rsc/pdf</code>,
|
||||
ensuring that the code can be moved without breaking users.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The check is at build time, not download time, so if <code>go</code> <code>get</code>
|
||||
fails because of this check, the mis-imported package has been copied to the local machine
|
||||
and should be removed manually.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
To complement this new feature, a check has been added at update time to verify
|
||||
that the local package's remote repository matches that of its custom import.
|
||||
The <code>go</code> <code>get</code> <code>-u</code> command will fail to
|
||||
update a package if its remote repository has changed since it was first
|
||||
downloaded.
|
||||
The new <code>-f</code> flag overrides this check.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Further information is in
|
||||
<a href="http://golang.org/s/go14customimport">the design document</a>.
|
||||
</p>
|
||||
|
||||
<h3 id="gogenerate">The go generate subcommand</h3>
|
||||
|
||||
<p>
|
||||
The <a href="/cmd/go/"><code>go</code></a> command has a new subcommand,
|
||||
<a href="/cmd/go/#hdr-Generate_Go_files_by_processing_source"><code>go generate</code></a>,
|
||||
to automate the running of tools to generate source code before compilation.
|
||||
For example, it can be used to run the <a href="/cmd/yacc"><code>yacc</code></a>
|
||||
compiler-compiler on a <code>.y</code> file to produce the Go source file implementing the grammar,
|
||||
or to automate the generation of <code>String</code> methods for typed constants using the new
|
||||
<a href="http://godoc.org/code.google.com/p/go.tools/cmd/stringer">stringer</a>
|
||||
tool in the <code>go.tools</code> repository.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
For more information, see the
|
||||
<a href="http://golang.org/s/go1.4-generate">design document</a>.
|
||||
</p>
|
||||
|
||||
<h3 id="filenames">Change to file name handling</h3>
|
||||
|
||||
<p>
|
||||
Build constraints, also known as build tags, control compilation by including or excluding files
|
||||
(see the documentation <a href="/pkg/go/build/"><code>/go/build</code></a>).
|
||||
Compilation can also be controlled by the name of the file itself by "tagging" the file with
|
||||
a suffix (before the <code>.go</code> or <code>.s</code> extension) with an underscore
|
||||
and the name of the architecture or operating system.
|
||||
For instance, the file <code>gopher_arm.go</code> will only be compiled if the target
|
||||
processor is an ARM.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Before Go 1.4, a file called just <code>arm.go</code> was similarly tagged, but this behavior
|
||||
can break sources when new architectures are added, causing files to suddenly become tagged.
|
||||
In 1.4, therefore, a file will be tagged in this manner only if the tag (architecture or operating
|
||||
system name) is preceded by an underscore.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<em>Updating</em>: Packages that depend on the old behavior will no longer compile correctly.
|
||||
Files with names like <code>windows.go</code> or <code>amd64.go</code> should either
|
||||
have explicit build tags added to the source or be renamed to something like
|
||||
<code>os_windows.go</code> or <code>support_amd64.go</code>.
|
||||
</p>
|
||||
|
||||
<h3 id="gocmd">Other changes to the go command</h3>
|
||||
|
||||
<p>
|
||||
There were a number of minor changes to the
|
||||
<a href="/cmd/go/"><code>cmd/go</code></a>
|
||||
command worth noting.
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
Unless <a href="/cmd/cgo/"><code>cgo</code></a> is being used to build the package,
|
||||
the <code>go</code> command now refuses to compile C source files,
|
||||
since the relevant C compilers
|
||||
(<a href="/cmd/6c/"><code>6c</code></a> etc.)
|
||||
are intended to be removed from the installation in some future release.
|
||||
(They are used today only to build part of the runtime.)
|
||||
It is difficult to use them correctly in any case, so any extant uses are likely incorrect,
|
||||
so we have disabled them.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/cmd/go/#hdr-Test_packages"><code>go</code> <code>test</code></a>
|
||||
subcommand has a new flag, <code>-o</code>, to set the name of the resulting binary,
|
||||
corresponding to the same flag in other subcommands.
|
||||
The non-functional <code>-file</code> flag has been removed.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/cmd/go/#hdr-Test_packages"><code>go</code> <code>test</code></a>
|
||||
subcommand will compile and link all <code>*_test.go</code> files in the package,
|
||||
even when there are no <code>Test</code> functions in them.
|
||||
It previously ignored such files.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The behavior of the
|
||||
<a href="/cmd/go/#hdr-Test_packages"><code>go</code> <code>build</code></a>
|
||||
subcommand's
|
||||
<code>-a</code> flag has been changed for non-development installations.
|
||||
For installations running a released distribution, the <code>-a</code> flag will no longer
|
||||
rebuild the standard library and commands, to avoid overwriting the installation's files.
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
<h3 id="pkg">Changes to package source layout</h3>
|
||||
|
||||
<p>
|
||||
In the main Go source repository, the source code for the packages was kept in
|
||||
the directory <code>src/pkg</code>, which made sense but differed from
|
||||
other repositories, including the Go sub-repositories such as <code>go.tools</code>.
|
||||
In Go 1.4, the<code> pkg</code> level of the source tree is now gone, so for example
|
||||
the <a href="/pkg/fmt/"><code>fmt</code></a> package's source, once kept in
|
||||
directory <code>src/pkg/fmt</code>, now lives one level higher in <code>src/fmt</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<em>Updating</em>: Tools like <code>godoc</code> that discover source code
|
||||
need to know about the new location. All tools and services maintained by the Go team
|
||||
have been updated.
|
||||
</p>
|
||||
|
||||
|
||||
<h3 id="swig">SWIG</h3>
|
||||
|
||||
<p>
|
||||
Due to the runtime changes in this release, Go 1.4 will require SWIG 3.0.3.
|
||||
At time of writing that has not yet been released, but we expect it to be by
|
||||
Go 1.4's release date.
|
||||
TODO
|
||||
</p>
|
||||
|
||||
<h3 id="misc">Miscellany</h3>
|
||||
|
||||
<p>
|
||||
The standard repository's top-level <code>misc</code> directory used to contain
|
||||
Go support for editors and IDEs: plugins, initialization scripts and so on.
|
||||
Maintaining these was becoming time-consuming
|
||||
and needed external help because many of the editors listed were not used by
|
||||
members of the core team.
|
||||
It also required us to make decisions about which plugin was best for a given
|
||||
editor, even for editors we do not use.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The Go community at large is much better suited to managing this information.
|
||||
In Go 1.4, therefore, this support has been removed from the repository.
|
||||
Instead, there is a curated, informative list of what's available on
|
||||
a <a href="https://code.google.com/p/go-wiki/wiki/IDEsAndTextEditorPlugins">wiki page</a>.
|
||||
</p>
|
||||
|
||||
<h2 id="performance">Performance</h2>
|
||||
|
||||
<p>
|
||||
Most programs will run about the same speed or slightly faster in 1.4 than in 1.3;
|
||||
some will be slightly slower.
|
||||
There are many changes, making it hard to be precise about what to expect.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
As mentioned above, much of the runtime was translated to Go from C,
|
||||
which led to some reduction in heap sizes.
|
||||
It also improved performance slightly because the Go compiler is better
|
||||
at optimization, due to things like inlining, than the C compiler used to build
|
||||
the runtime.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The garbage collector was sped up, leading to measurable improvements for
|
||||
garbage-heavy programs.
|
||||
On the other hand, the new write barriers slow things down again, typically
|
||||
by about the same amount but, depending on their behavior, some programs
|
||||
may be somewhat slower or faster.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Library changes that affect performance are documented below.
|
||||
</p>
|
||||
|
||||
<h2 id="library">Changes to the standard library</h2>
|
||||
|
||||
<h3 id="new_packages">New packages</h3>
|
||||
|
||||
<p>
|
||||
There are no new packages in this release.
|
||||
</p>
|
||||
|
||||
<h3 id="major_library_changes">Major changes to the library</h3>
|
||||
|
||||
<h4 id="scanner">bufio.Scanner</h4>
|
||||
|
||||
<p>
|
||||
The <a href="/pkg/bufio/#Scanner"><code>Scanner</code></a> type in the
|
||||
<a href="/pkg/bufio/"><code>bufio</code></a> package
|
||||
has had a bug fixed that may require changes to custom
|
||||
<a href="/pkg/bufio/#SplitFunc"><code>split functions</code></a>.
|
||||
The bug made it impossible to generate an empty token at EOF; the fix
|
||||
changes the end conditions seen by the split function.
|
||||
Previously, scanning stopped at EOF if there was no more data.
|
||||
As of 1.4, the split function will be called once at EOF after input is exhausted,
|
||||
so the split function can generate a final empty token
|
||||
as the documentation already promised.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<em>Updating</em>: Custom split functions may need to be modified to
|
||||
handle empty tokens at EOF as desired.
|
||||
</p>
|
||||
|
||||
<h4 id="syscall">syscall</h4>
|
||||
|
||||
<p>
|
||||
The <a href="/pkg/syscall/"><code>syscall</code></a> package is now frozen except
|
||||
for changes needed to maintain the core repository.
|
||||
In particular, it will no longer be extended to support new or different system calls
|
||||
that are not used by the core.
|
||||
The reasons are described at length in <a href="http://golang.org/s/go1.4-syscall">a
|
||||
separate document</a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
A new subrepository, <a href="http://code.google.com/p/go.sys">go.sys</a>,
|
||||
has been created to serve as the location for new developments to support system
|
||||
calls on all kernels.
|
||||
It has a nicer structure, with three packages that each hold the implementation of
|
||||
system calls for one of
|
||||
<a href="http://godoc.org/code.google.com/p/go.sys/unix">Unix</a>,
|
||||
<a href="http://godoc.org/code.google.com/p/go.sys/windows">Windows</a> and
|
||||
<a href="http://godoc.org/code.google.com/p/go.sys/plan9">Plan 9</a>.
|
||||
These packages will be curated more generously, accepting all reasonable changes
|
||||
that reflect kernel interfaces in those operating systems.
|
||||
See the documentation and the article mentioned above for more information.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<em>Updating</em>: Existing programs are not affected as the <code>syscall</code>
|
||||
package is largely unchanged from the 1.3 release.
|
||||
Future development that requires system calls not in the <code>syscall</code> package
|
||||
should build on <code>go.sys</code> instead.
|
||||
</p>
|
||||
|
||||
<h3 id="minor_library_changes">Minor changes to the library</h3>
|
||||
|
||||
<p>
|
||||
The following list summarizes a number of minor changes to the library, mostly additions.
|
||||
See the relevant package documentation for more information about each change.
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/compress/flate/"><code>compress/flate</code></a>,
|
||||
<a href="/pkg/compress/gzip/"><code>compress/gzip</code></a>,
|
||||
and <a href="/pkg/compress/zlib/"><code>compress/zlib</code></a>
|
||||
packages now support a <code>Reset</code> method
|
||||
for the decompressors, allowing them to reuse buffers and improve performance.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/crypto/tls/"><code>crypto/tls</code></a> package
|
||||
now supports ALPN as defined in <a href="http://tools.ietf.org/html/rfc7301">RFC 7301</a>.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/crypto/tls/"><code>crypto/tls</code></a> package
|
||||
now supports programmatic selection of server certificates
|
||||
through the new <a href="/pkg/crypto/tls/#Config.CertificateForName"><code>CertificateForName</code></a> function
|
||||
of the <a href="/pkg/crypo/tls/#Config"><code>Config</code></a> struct.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
Also in the crypto/tls package, the server now supports
|
||||
<a href="https://tools.ietf.org/html/draft-ietf-tls-downgrade-scsv-00">TLS_FALLBACK_SCSV</a>
|
||||
to help clients detect fallback attacks.
|
||||
(The Go client does not support fallback at all, so it is not vulnerable to
|
||||
those attacks.)
|
||||
</li>
|
||||
|
||||
<li>
|
||||
In the <a href="/pkg/encoding/asn1/"><code>encoding/asn1</code></a> package,
|
||||
optional elements with a default value will now only be omitted if they have that value.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/encoding/csv/"><code>encoding/csv</code></a> package no longer
|
||||
quotes empty strings but does quote the end-of-data marker <code>\.</code> (backslash dot).
|
||||
This is permitted by the definition of CSV and allows it to work better with Postgres.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/encoding/gob/"><code>encoding/gob</code></a> package has been rewritten to eliminate
|
||||
the use of unsafe operations, allowing it to be used in environments that do not permit use of the
|
||||
<a href="/pkg/unsafe/"><code>unsafe</code></a> package.
|
||||
For typical uses it will be 10-30% slower, but the delta is dependent on the type of the data and
|
||||
in some cases, especially involving arrays, it can be faster.
|
||||
There is no functional change.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
In the <a href="/pkg/fmt/"><code>fmt</code></a> package,
|
||||
formatting of pointers to maps has changed to be consistent with that of pointers
|
||||
to structs, arrays, and so on.
|
||||
For instance, <code>&map[string]int{"one":</code> <code>1}</code> now prints by default as
|
||||
<code>&map[one:</code> <code>1]</code> rather than as a hexadecimal pointer value.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/net/http/"><code>net/http</code></a> package's
|
||||
<a href="/pkg/net/http/#Request"><code>Request</code></a> type
|
||||
has a new <a href="/pkg/net/http/#Request.BasicAuth"><code>BasicAuth</code></a> method
|
||||
that returns the username and password from authenticated requests using the
|
||||
HTTP Basic Authentication
|
||||
Scheme.
|
||||
</li>
|
||||
|
||||
<li>The <a href="/pkg/net/http/"><code>net/http</code></a> package's
|
||||
<a href="/pkg/net/http/#Request"><code>Transport</code></a> type
|
||||
has a new <a href="/pkg/net/http/#Transport.DialTLS"><code>DialTLS</code></a> hook
|
||||
that allows customizing the behavior of outbound TLS connections.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/net/http/httputil/"><code>net/http/httputil</code></a> package's
|
||||
<a href="/pkg/net/http/httputil/#ReverseProxy"><code>ReverseProxy</code></a> type
|
||||
has a new field,
|
||||
<a href="/pkg/net/http/#ReverseProxy.ErrorLog"><code>ErrorLog</code></a>, that
|
||||
provides user control of logging.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/os/"><code>os</code></a> package
|
||||
now implements symbolic links on the Windows operating system
|
||||
through the <a href="/pkg/os/#Symlink"><code>Symlink</code></a> function.
|
||||
Other operating systems already have this functionality.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/reflect/"><code>reflect</code></a> package's
|
||||
<a href="/pkg/reflect/#Type"><code>Type</code></a> interface
|
||||
has a new method, <a href="/pkg/reflect/#type.Comparable"><code>Comparable</code></a>,
|
||||
that reports whether the type implements general comparisons.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
Also in the <a href="/pkg/reflect/"><code>reflect</code></a> package, the
|
||||
<a href="/pkg/reflect/#Value"><code>Value</code></a> interface is now three instead of four words
|
||||
because of changes to the implementation of interfaces in the runtime.
|
||||
This saves memory but has no semantic effect.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/runtime/"><code>runtime</code></a> package
|
||||
now implements monotonic clocks on Windows,
|
||||
as it already did for the other systems.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/runtime/"><code>runtime</code></a> package's
|
||||
<a href="/pkg/runtime/#MemStats.Mallocs"><code>Mallocs</code></a> counter
|
||||
now counts very small allocations that were missed in Go 1.3.
|
||||
This may break tests using <a href="/pkg/runtime/#ReadMemStats"><code>ReadMemStats</code></a>
|
||||
or <a href="/pkg/testing/#AllocsPerRun"><code>AllocsPerRun</code></a>
|
||||
due to the more accurate answer.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
In the <a href="/pkg/runtime/"><code>runtime</code></a> package,
|
||||
an array <a href="/pkg/runtime/#MemStats.PauseEnd"><code>PauseEnd</code></a>
|
||||
has been added to the
|
||||
<a href="/pkg/runtime/#MemStats"><code>MemStats</code></a>
|
||||
and <a href="/pkg/runtime/#GCStats"><code>GCStats</code></a> structs.
|
||||
This array is a circular buffer of times when garbage collection pauses ended.
|
||||
The corresponding pause durations are already recorded in
|
||||
<a href="/pkg/runtime/#MemStats.PauseNs"><code>PauseNs</code></a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/runtime/race/"><code>runtime/race</code></a> package
|
||||
now supports FreeBSD, which means the
|
||||
<a href="/pkg/cmd/go/"><code>go</code></a> command's <code>-race</code>
|
||||
flag now works on FreeBSD.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/sync/atomic/"><code>sync/atomic</code></a> package
|
||||
has a new type, <a href="/pkg/sync/atomic/#Value"><code>Value</code></a>.
|
||||
<code>Value</code> provides an efficient mechanism for atomic loads and
|
||||
stores of values of arbitrary type.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
In the <a href="/pkg/syscall/"><code>syscall</code></a> package's
|
||||
implementation on Linux, the
|
||||
<a href="/pkg/syscall/#Setuid"><code>Setuid</code></a>
|
||||
and <a href="/pkg/syscall/#Setgid"><code>Setgid</code></a> have been disabled
|
||||
because those system calls operate on the calling thread, not the whole process, which is
|
||||
different from other platforms and not the expected result.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/testing/"><code>testing</code></a> package
|
||||
has a new facility to provide more control over running a set of tests.
|
||||
If the test code contains a function
|
||||
<pre>
|
||||
func TestMain(m *<a href="/pkg/testing/#M"><code>testing.M</code></a>)
|
||||
</pre>
|
||||
|
||||
that function will be called instead of running the tests directly.
|
||||
The <code>M</code> struct contains methods to access and run the tests.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
Also in the <a href="/pkg/testing/"><code>testing</code></a> package,
|
||||
a new <a href="/pkg/testing/#Coverage"><code>Coverage</code></a>
|
||||
function reports the current test coverage fraction,
|
||||
enabling individual tests to report how much they are contributing to the
|
||||
overall coverage.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/text/scanner/"><code>text/scanner</code></a> package's
|
||||
<a href="/pkg/text/scanner/#Scanner"><code>Scanner</code></a> type
|
||||
has a new function,
|
||||
<a href="/pkg/text/scanner/#Scanner.IsIdentRune"><code>IsIdentRune</code></a>,
|
||||
allowing one to control the definition of an identifier when scanning.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/text/template/"><code>text/template</code></a> package's boolean
|
||||
functions <code>eq</code>, <code>lt</code>, and so on have been generalized to allow comparison
|
||||
of signed and unsigned integers, simplifying their use in practice.
|
||||
(Previously one could only compare values of the same signedness.)
|
||||
All negative values compare less than all unsigned values.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <code>time</code> package now uses the standard symbol for the micro prefix,
|
||||
the micro symbol (U+00B5 'µ'), to print microsecond durations.
|
||||
<a href="/pkg/time/#ParseDuration"><code>ParseDuration</code></a> still accepts <code>us</code>
|
||||
but the package no longer prints microseconds as <code>us</code>.
|
||||
<br>
|
||||
<em>Updating</em>: Code that depends on the output format of durations
|
||||
but does not use ParseDuration will need to be updated.
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
2038
doc/go1.html
@@ -1,190 +0,0 @@
|
||||
<!--{
|
||||
"Title": "Go 1 and the Future of Go Programs",
|
||||
"Path": "/doc/go1compat"
|
||||
}-->
|
||||
|
||||
<h2 id="introduction">Introduction</h2>
|
||||
<p>
|
||||
The release of Go version 1, Go 1 for short, is a major milestone
|
||||
in the development of the language. Go 1 is a stable platform for
|
||||
the growth of programs and projects written in Go.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Go 1 defines two things: first, the specification of the language;
|
||||
and second, the specification of a set of core APIs, the "standard
|
||||
packages" of the Go library. The Go 1 release includes their
|
||||
implementation in the form of two compiler suites (gc and gccgo),
|
||||
and the core libraries themselves.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
It is intended that programs written to the Go 1 specification will
|
||||
continue to compile and run correctly, unchanged, over the lifetime
|
||||
of that specification. At some indefinite point, a Go 2 specification
|
||||
may arise, but until that time, Go programs that work today should
|
||||
continue to work even as future "point" releases of Go 1 arise (Go
|
||||
1.1, Go 1.2, etc.).
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Compatibility is at the source level. Binary compatibility for
|
||||
compiled packages is not guaranteed between releases. After a point
|
||||
release, Go source will need to be recompiled to link against the
|
||||
new release.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The APIs may grow, acquiring new packages and features, but not in
|
||||
a way that breaks existing Go 1 code.
|
||||
</p>
|
||||
|
||||
<h2 id="expectations">Expectations</h2>
|
||||
|
||||
<p>
|
||||
Although we expect that the vast majority of programs will maintain
|
||||
this compatibility over time, it is impossible to guarantee that
|
||||
no future change will break any program. This document is an attempt
|
||||
to set expectations for the compatibility of Go 1 software in the
|
||||
future. There are a number of ways in which a program that compiles
|
||||
and runs today may fail to do so after a future point release. They
|
||||
are all unlikely but worth recording.
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
Security. A security issue in the specification or implementation
|
||||
may come to light whose resolution requires breaking compatibility.
|
||||
We reserve the right to address such security issues.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
Unspecified behavior. The Go specification tries to be explicit
|
||||
about most properties of the language, but there are some aspects
|
||||
that are undefined. Programs that depend on such unspecified behavior
|
||||
may break in future releases.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
Specification errors. If it becomes necessary to address an
|
||||
inconsistency or incompleteness in the specification, resolving the
|
||||
issue could affect the meaning or legality of existing programs.
|
||||
We reserve the right to address such issues, including updating the
|
||||
implementations. Except for security issues, no incompatible changes
|
||||
to the specification would be made.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
Bugs. If a compiler or library has a bug that violates the
|
||||
specification, a program that depends on the buggy behavior may
|
||||
break if the bug is fixed. We reserve the right to fix such bugs.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
Struct literals. For the addition of features in later point
|
||||
releases, it may be necessary to add fields to exported structs in
|
||||
the API. Code that uses unkeyed struct literals (such as pkg.T{3,
|
||||
"x"}) to create values of these types would fail to compile after
|
||||
such a change. However, code that uses keyed literals (pkg.T{A:
|
||||
3, B: "x"}) will continue to compile after such a change. We will
|
||||
update such data structures in a way that allows keyed struct
|
||||
literals to remain compatible, although unkeyed literals may fail
|
||||
to compile. (There are also more intricate cases involving nested
|
||||
data structures or interfaces, but they have the same resolution.)
|
||||
We therefore recommend that composite literals whose type is defined
|
||||
in a separate package should use the keyed notation.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
Dot imports. If a program imports a standard package
|
||||
using <code>import . "path"</code>, additional names defined in the
|
||||
imported package in future releases may conflict with other names
|
||||
defined in the program. We do not recommend the use of <code>import .</code>
|
||||
outside of tests, and using it may cause a program to fail
|
||||
to compile in future releases.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
Use of package <code>unsafe</code>. Packages that import
|
||||
<a href="/pkg/unsafe/"><code>unsafe</code></a>
|
||||
may depend on internal properties of the Go implementation.
|
||||
We reserve the right to make changes to the implementation
|
||||
that may break such programs.
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
Of course, for all of these possibilities, should they arise, we
|
||||
would endeavor whenever feasible to update the specification,
|
||||
compilers, or libraries without affecting existing code.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
These same considerations apply to successive point releases. For
|
||||
instance, code that runs under Go 1.2 should be compatible with Go
|
||||
1.2.1, Go 1.3, Go 1.4, etc., although not necessarily with Go 1.1
|
||||
since it may use features added only in Go 1.2
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Features added between releases, available in the source repository
|
||||
but not part of the numbered binary releases, are under active
|
||||
development. No promise of compatibility is made for software using
|
||||
such features until they have been released.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Finally, although it is not a correctness issue, it is possible
|
||||
that the performance of a program may be affected by
|
||||
changes in the implementation of the compilers or libraries upon
|
||||
which it depends.
|
||||
No guarantee can be made about the performance of a
|
||||
given program between releases.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Although these expectations apply to Go 1 itself, we hope similar
|
||||
considerations would be made for the development of externally
|
||||
developed software based on Go 1.
|
||||
</p>
|
||||
|
||||
<h2 id="subrepos">Sub-repositories</h2>
|
||||
|
||||
<p>
|
||||
Code in sub-repositories of the main go tree, such as
|
||||
<a href="//code.google.com/p/go.net">code.google.com/p/go.net</a>,
|
||||
may be developed under
|
||||
looser compatibility requirements. However, the sub-repositories
|
||||
will be tagged as appropriate to identify versions that are compatible
|
||||
with the Go 1 point releases.
|
||||
</p>
|
||||
|
||||
<h2 id="operating_systems">Operating systems</h2>
|
||||
|
||||
<p>
|
||||
It is impossible to guarantee long-term compatibility with operating
|
||||
system interfaces, which are changed by outside parties.
|
||||
The <a href="/pkg/syscall/"><code>syscall</code></a> package
|
||||
is therefore outside the purview of the guarantees made here.
|
||||
As of Go version 1.4, the <code>syscall</code> package is frozen.
|
||||
Any evolution of the system call interface must be supported elsewhere,
|
||||
such as in the
|
||||
<a href="http://godoc.org/code.google.com/p/go.sys">go.sys</a> subrepository.
|
||||
For details and background, see
|
||||
<a href="https://golang.org/s/go1.4-syscall">this document</a>.
|
||||
</p>
|
||||
|
||||
<h2 id="tools">Tools</h2>
|
||||
|
||||
<p>
|
||||
Finally, the Go tool chain (compilers, linkers, build tools, and so
|
||||
on) are under active development and may change behavior. This
|
||||
means, for instance, that scripts that depend on the location and
|
||||
properties of the tools may be broken by a point release.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
These caveats aside, we believe that Go 1 will be a firm foundation
|
||||
for the development of Go and its ecosystem.
|
||||
</p>
|
||||
1127
doc/go_faq.html
707
doc/go_for_cpp_programmers.html
Normal file
@@ -0,0 +1,707 @@
|
||||
<!-- Go For C++ Programmers -->
|
||||
|
||||
<p>
|
||||
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.
|
||||
|
||||
<p>
|
||||
For a more general introduction to Go, see the
|
||||
<a href="go_tutorial.html">Go tutorial</a> and
|
||||
<a href="effective_go.html">Effective Go</a>.
|
||||
|
||||
<p>
|
||||
For a detailed description of the Go language, see the
|
||||
<a href="go_spec.html">Go spec</a>.
|
||||
|
||||
<h2 id="Conceptual_Differences">Conceptual Differences</h2>
|
||||
|
||||
<ul>
|
||||
<li>Go does not have classes with constructors or destructors.
|
||||
Instead of class methods, a class inheritance hierarchy,
|
||||
and virtual functions, Go provides <em>interfaces</em>, which are
|
||||
<a href="#Interfaces">discussed in more detail below</a>.
|
||||
Interfaces are also used where C++ uses templates.
|
||||
|
||||
<li>Go uses garbage collection. It is not necessary (or possible)
|
||||
to release memory explicitly. The garbage collection is (intended to be)
|
||||
incremental and highly efficient on modern processors.
|
||||
|
||||
<li>Go has pointers but not pointer arithmetic. You cannot
|
||||
use a pointer variable to walk through the bytes of a string.
|
||||
|
||||
<li>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; slices hold pointers to underlying arrays. Slices
|
||||
are <a href="#Slices">discussed further below</a>.
|
||||
|
||||
<li>Strings are provided by the language. They may not be changed once they
|
||||
have been created.
|
||||
|
||||
<li>Hash tables are provided by the language. They are called maps.
|
||||
|
||||
<li>Separate threads of execution, and communication channels between
|
||||
them, are provided by the language. This
|
||||
is <a href="#Goroutines">discussed further below</a>.
|
||||
|
||||
<li>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. In C++ terms, one can
|
||||
think of these as being reference types.
|
||||
|
||||
<li>Go does not use header files. Instead, each source file is part of a
|
||||
defined <em>package</em>. When a package defines an object
|
||||
(type, constant, variable, function) with a name starting with an
|
||||
upper case letter, that object is visible to any other file which
|
||||
imports that package.
|
||||
|
||||
<li>Go does not support implicit type conversion. Operations that mix
|
||||
different types require casts (called conversions in Go).
|
||||
|
||||
<li>Go does not support function overloading and does not support user
|
||||
defined operators.
|
||||
|
||||
<li>Go does not support <code>const</code> or <code>volatile</code> qualifiers.
|
||||
|
||||
<li>Go uses <code>nil</code> for invalid pointers, where C++ uses
|
||||
<code>NULL</code> or simply <code>0</code>.
|
||||
</ul>
|
||||
|
||||
<h2 id="Syntax">Syntax</h2>
|
||||
|
||||
<p>
|
||||
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.
|
||||
|
||||
<pre>
|
||||
<b>Go C++</b>
|
||||
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);
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Declarations generally take the form of a keyword followed by the name
|
||||
of the object being declared. The keyword is one of <code>var</code>,
|
||||
<code>func</code>,
|
||||
<code>const</code>, or <code>type</code>. Method declarations are a minor
|
||||
exception in that
|
||||
the receiver appears before the name of the object being declared; see
|
||||
the <a href="#Interfaces">discussion of interfaces</a>.
|
||||
|
||||
<p>
|
||||
You can also use a keyword followed by a series of declarations in
|
||||
parentheses.
|
||||
|
||||
<pre>
|
||||
var (
|
||||
i int
|
||||
m float64
|
||||
)
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
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:
|
||||
|
||||
<pre>
|
||||
func f(i, j, k int, s, t string)
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
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.
|
||||
|
||||
<pre>
|
||||
var v = *p
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
See also the <a href="#Constants">discussion of constants, below</a>.
|
||||
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.
|
||||
|
||||
<p>
|
||||
Within a function, a short declaration syntax is available with
|
||||
<code>:=</code> .
|
||||
|
||||
<pre>
|
||||
v1 := v2
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
This is equivalent to
|
||||
|
||||
<pre>
|
||||
var v1 = v2
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Go permits multiple assignments, which are done in parallel.
|
||||
|
||||
<pre>
|
||||
i, j = j, i // Swap i and j.
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
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.
|
||||
|
||||
<pre>
|
||||
func f() (i int, j int) { ... }
|
||||
v1, v2 = f()
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
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 <a href="go_spec.html#Semicolons">the language specification</a>).
|
||||
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
|
||||
<pre>
|
||||
func g()
|
||||
{ // INVALID
|
||||
}
|
||||
</pre>
|
||||
A semicolon will be inserted after <code>g()</code>, causing it to be
|
||||
a function declaration rather than a function definition. Similarly,
|
||||
you may not write
|
||||
<pre>
|
||||
if x {
|
||||
}
|
||||
else { // INVALID
|
||||
}
|
||||
</pre>
|
||||
A semicolon will be inserted after the <code>}</code> preceding
|
||||
the <code>else</code>, causing a syntax error.
|
||||
|
||||
<p>
|
||||
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 <code>for</code> loop clause and cases where you want several
|
||||
short statements on a single line.
|
||||
|
||||
<p>
|
||||
While we're on the topic, we recommend that rather than worry about
|
||||
semicolons and brace placement, you format your code with
|
||||
the <code>gofmt</code> 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.
|
||||
|
||||
<p>
|
||||
When using a pointer to a struct, you use <code>.</code> instead
|
||||
of <code>-></code>.
|
||||
Thus syntactically speaking a structure and a pointer to a structure
|
||||
are used in the same way.
|
||||
|
||||
<pre>
|
||||
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)
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Go does not require parentheses around the condition of a <code>if</code>
|
||||
statement, or the expressions of a <code>for</code> statement, or the value of a
|
||||
<code>switch</code> statement. On the other hand, it does require curly braces
|
||||
around the body of an <code>if</code> or <code>for</code> statement.
|
||||
|
||||
<pre>
|
||||
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
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Go does not have a <code>while</code> statement nor does it have a
|
||||
<code>do/while</code>
|
||||
statement. The <code>for</code> statement may be used with a single condition,
|
||||
which makes it equivalent to a <code>while</code> statement. Omitting the
|
||||
condition entirely is an endless loop.
|
||||
|
||||
<p>
|
||||
Go permits <code>break</code> and <code>continue</code> to specify a label.
|
||||
The label must
|
||||
refer to a <code>for</code>, <code>switch</code>, or <code>select</code>
|
||||
statement.
|
||||
|
||||
<p>
|
||||
In a <code>switch</code> statement, <code>case</code> labels do not fall
|
||||
through. You can
|
||||
make them fall through using the <code>fallthrough</code> keyword. This applies
|
||||
even to adjacent cases.
|
||||
|
||||
<pre>
|
||||
switch i {
|
||||
case 0: // empty case body
|
||||
case 1:
|
||||
f() // f is not called when i == 0!
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
But a <code>case</code> can have multiple values.
|
||||
|
||||
<pre>
|
||||
switch i {
|
||||
case 0, 1:
|
||||
f() // f is called if i == 0 || i == 1.
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The values in a <code>case</code> 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 <code>switch</code>
|
||||
value is omitted it defaults to <code>true</code>.
|
||||
|
||||
<pre>
|
||||
switch {
|
||||
case i < 0:
|
||||
f1()
|
||||
case i == 0:
|
||||
f2()
|
||||
case i > 0:
|
||||
f3()
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The <code>++</code> and <code>--</code> operators may only be used in
|
||||
statements, not in expressions.
|
||||
You cannot write <code>c = *p++</code>. <code>*p++</code> is parsed as
|
||||
<code>(*p)++</code>.
|
||||
|
||||
<p>
|
||||
The <code>defer</code> statement may be used to call a function after
|
||||
the function containing the <code>defer</code> statement returns.
|
||||
|
||||
<pre>
|
||||
fd := open("filename")
|
||||
defer close(fd) // fd will be closed when this function returns.
|
||||
</pre>
|
||||
|
||||
<h2 id="Constants">Constants </h2>
|
||||
|
||||
<p>
|
||||
In Go constants may be <i>untyped</i>. This applies even to constants
|
||||
named with a <code>const</code> 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.
|
||||
|
||||
<pre>
|
||||
var a uint
|
||||
f(a + 1) // untyped numeric constant "1" becomes typed as uint
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
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.
|
||||
|
||||
<pre>
|
||||
const huge = 1 << 100
|
||||
f(huge >> 98)
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Go does not support enums. Instead, you can use the special name
|
||||
<code>iota</code> in a single <code>const</code> declaration to get a
|
||||
series of increasing
|
||||
value. When an initialization expression is omitted for a <code>const</code>,
|
||||
it reuses the preceding expression.
|
||||
|
||||
<pre>
|
||||
const (
|
||||
red = iota // red == 0
|
||||
blue // blue == 1
|
||||
green // green == 2
|
||||
)
|
||||
</pre>
|
||||
|
||||
<h2 id="Slices">Slices</h2>
|
||||
|
||||
<p>
|
||||
A slice is conceptually a struct with three fields: a
|
||||
pointer to an array, a length, and a capacity.
|
||||
Slices support
|
||||
the <code>[]</code> operator to access elements of the underlying array.
|
||||
The builtin
|
||||
<code>len</code> function returns the
|
||||
length of the slice. The builtin <code>cap</code> function returns the
|
||||
capacity.
|
||||
|
||||
<p>
|
||||
Given an array, or another slice, a new slice is created via
|
||||
<code>a[I:J]</code>. This
|
||||
creates a new slice which refers to <code>a</code>, starts at
|
||||
index <code>I</code>, and ends before index
|
||||
<code>J</code>. It has length <code>J - I</code>.
|
||||
The new slice refers to the same array
|
||||
to which <code>a</code>
|
||||
refers. That is, changes made using the new slice may be seen using
|
||||
<code>a</code>. The
|
||||
capacity of the new slice is simply the capacity of <code>a</code> minus
|
||||
<code>I</code>. 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 <code>var s []int; var a[10] int</code>,
|
||||
the assignment <code>s = &a</code> is equivalent to
|
||||
<code>s = a[0:len(a)]</code>.
|
||||
|
||||
<p>
|
||||
What this means is that Go uses slices for some cases where C++ uses pointers.
|
||||
If you create a value of type <code>[100]byte</code> (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 <code>[]byte</code>, 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
|
||||
<code>len</code>.
|
||||
|
||||
<p>
|
||||
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.
|
||||
|
||||
<h2 id="Making_values">Making values</h2>
|
||||
|
||||
<p>
|
||||
Go has a builtin function <code>new</code> which takes a type and
|
||||
allocates space
|
||||
on the heap. The allocated space will be zero-initialized for the type.
|
||||
For example, <code>new(int)</code> allocates a new int on the heap,
|
||||
initializes it with the value <code>0</code>,
|
||||
and returns its address, which has type <code>*int</code>.
|
||||
Unlike in C++, <code>new</code> is a function, not an operator;
|
||||
<code>new int</code> is a syntax error.
|
||||
|
||||
<p>
|
||||
Map and channel values must be allocated using the builtin function
|
||||
<code>make</code>.
|
||||
A variable declared with map or channel type without an initializer will be
|
||||
automatically initialized to <code>nil</code>.
|
||||
Calling <code>make(map[int]int)</code> returns a newly allocated value of
|
||||
type <code>map[int]int</code>.
|
||||
Note that <code>make</code> returns a value, not a pointer. This is
|
||||
consistent with
|
||||
the fact that map and channel values are passed by reference. Calling
|
||||
<code>make</code> with
|
||||
a map type takes an optional argument which is the expected capacity of the
|
||||
map. Calling <code>make</code> with a channel type takes an optional
|
||||
argument which sets the
|
||||
buffering capacity of the channel; the default is 0 (unbuffered).
|
||||
|
||||
<p>
|
||||
The <code>make</code> 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,
|
||||
<code>make([]int, 10, 20)</code>. This is identical to
|
||||
<code>new([20]int)[0:10]</code>. Since
|
||||
Go uses garbage collection, the newly allocated array will be discarded
|
||||
sometime after there are no references to the returned slice.
|
||||
|
||||
<h2 id="Interfaces">Interfaces</h2>
|
||||
|
||||
<p>
|
||||
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.
|
||||
|
||||
<p>
|
||||
A method looks like an ordinary function definition, except that it
|
||||
has a <em>receiver</em>. The receiver is similar to
|
||||
the <code>this</code> pointer in a C++ class method.
|
||||
|
||||
<pre>
|
||||
type myType struct { i int }
|
||||
func (p *myType) get() int { return p.i }
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
This declares a method <code>get</code> associated with <code>myType</code>.
|
||||
The receiver is named <code>p</code> in the body of the function.
|
||||
|
||||
<p>
|
||||
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.
|
||||
|
||||
<p>
|
||||
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.
|
||||
|
||||
<pre>
|
||||
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.
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Given this interface:
|
||||
|
||||
<pre>
|
||||
type myInterface interface {
|
||||
get() int
|
||||
set(i int)
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
we can make <code>myType</code> satisfy the interface by adding
|
||||
|
||||
<pre>
|
||||
func (p *myType) set(i int) { p.i = i }
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Now any function which takes <code>myInterface</code> as a parameter
|
||||
will accept a
|
||||
variable of type <code>*myType</code>.
|
||||
|
||||
<pre>
|
||||
func getAndSet(x myInterface) {}
|
||||
func f1() {
|
||||
var p myType
|
||||
getAndSet(&p)
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
In other words, if we view <code>myInterface</code> as a C++ pure abstract
|
||||
base
|
||||
class, defining <code>set</code> and <code>get</code> for
|
||||
<code>*myType</code> made <code>*myType</code> automatically
|
||||
inherit from <code>myInterface</code>. A type may satisfy multiple interfaces.
|
||||
|
||||
<p>
|
||||
An anonymous field may be used to implement something much like a C++ child
|
||||
class.
|
||||
|
||||
<pre>
|
||||
type myChildType struct { myType; j int }
|
||||
func (p *myChildType) get() int { p.j++; return p.myType.get() }
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
This effectively implements <code>myChildType</code> as a child of
|
||||
<code>myType</code>.
|
||||
|
||||
<pre>
|
||||
func f2() {
|
||||
var p myChildType
|
||||
getAndSet(&p)
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The <code>set</code> method is effectively inherited from
|
||||
<code>myChildType</code>, because
|
||||
methods associated with the anonymous field are promoted to become methods
|
||||
of the enclosing type. In this case, because <code>myChildType</code> has an
|
||||
anonymous field of type <code>myType</code>, the methods of
|
||||
<code>myType</code> also become methods of <code>myChildType</code>.
|
||||
In this example, the <code>get</code> method was
|
||||
overridden, and the <code>set</code> method was inherited.
|
||||
|
||||
<p>
|
||||
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.
|
||||
|
||||
<p>
|
||||
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++ <code>dynamic_cast</code>. Unlike
|
||||
<code>dynamic_cast</code>, there does
|
||||
not need to be any declared relationship between the two interfaces.
|
||||
|
||||
<pre>
|
||||
type myPrintInterface interface {
|
||||
print()
|
||||
}
|
||||
func f3(x myInterface) {
|
||||
x.(myPrintInterface).print() // type assertion to myPrintInterface
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The conversion to <code>myPrintInterface</code> is entirely dynamic.
|
||||
It will
|
||||
work as long as the underlying type of x (the <em>dynamic type</em>) defines
|
||||
a <code>print</code> method.
|
||||
|
||||
<p>
|
||||
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.
|
||||
|
||||
<pre>
|
||||
type Any interface { }
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Containers may be written in terms of <code>Any</code>, 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.
|
||||
|
||||
<pre>
|
||||
type iterator interface {
|
||||
get() Any
|
||||
set(v Any)
|
||||
increment()
|
||||
equal(arg *iterator) bool
|
||||
}
|
||||
</pre>
|
||||
|
||||
<h2 id="Goroutines">Goroutines</h2>
|
||||
|
||||
<p>
|
||||
Go permits starting a new thread of execution (a <em>goroutine</em>)
|
||||
using the <code>go</code>
|
||||
statement. The <code>go</code> statement runs a function in a
|
||||
different, newly created, goroutine.
|
||||
All goroutines in a single program share the same address space.
|
||||
|
||||
<p>
|
||||
Internally, goroutines act like coroutines that are multiplexed among
|
||||
multiple operating system threads. You do not have to worry
|
||||
about these details.
|
||||
|
||||
<pre>
|
||||
func server(i int) {
|
||||
for {
|
||||
print(i)
|
||||
sys.sleep(10)
|
||||
}
|
||||
}
|
||||
go server(1)
|
||||
go server(2)
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
(Note that the <code>for</code> statement in the <code>server</code>
|
||||
function is equivalent to a C++ <code>while (true)</code> loop.)
|
||||
|
||||
<p>
|
||||
Goroutines are (intended to be) cheap.
|
||||
|
||||
<p>
|
||||
Function literals (which Go implements as closures)
|
||||
can be useful with the <code>go</code> statement.
|
||||
|
||||
<pre>
|
||||
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.
|
||||
</pre>
|
||||
|
||||
<h2 id="Channels">Channels</h2>
|
||||
|
||||
<p>
|
||||
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 <code><-</code> as a binary
|
||||
operator. To
|
||||
receive a value on a channel, use <code><-</code> as a unary operator.
|
||||
When calling
|
||||
functions, channels are passed by reference.
|
||||
|
||||
<p>
|
||||
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.
|
||||
|
||||
<pre>
|
||||
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 }
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
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.
|
||||
|
||||
<pre>
|
||||
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 }
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
To use <code>manager2</code>, given a channel to it:
|
||||
|
||||
<pre>
|
||||
func f4(ch <- chan cmd2) int {
|
||||
myCh := make(chan int)
|
||||
c := cmd2{ true, 0, myCh } // Composite literal syntax.
|
||||
ch <- c
|
||||
return <-myCh
|
||||
}
|
||||
</pre>
|
||||
113
doc/go_mem.html
@@ -1,17 +1,4 @@
|
||||
<!--{
|
||||
"Title": "The Go Memory Model",
|
||||
"Subtitle": "Version of May 31, 2014",
|
||||
"Path": "/ref/mem"
|
||||
}-->
|
||||
|
||||
<style>
|
||||
p.rule {
|
||||
font-style: italic;
|
||||
}
|
||||
span.event {
|
||||
font-style: italic;
|
||||
}
|
||||
</style>
|
||||
<!-- The Go Memory Model -->
|
||||
|
||||
<h2>Introduction</h2>
|
||||
|
||||
@@ -21,29 +8,6 @@ reads of a variable in one goroutine can be guaranteed to
|
||||
observe values produced by writes to the same variable in a different goroutine.
|
||||
</p>
|
||||
|
||||
|
||||
<h2>Advice</h2>
|
||||
|
||||
<p>
|
||||
Programs that modify data being simultaneously accessed by multiple goroutines
|
||||
must serialize such access.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
To serialize access, protect the data with channel operations or other synchronization primitives
|
||||
such as those in the <a href="/pkg/sync/"><code>sync</code></a>
|
||||
and <a href="/pkg/sync/atomic/"><code>sync/atomic</code></a> packages.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If you must read the rest of this document to understand the behavior of your program,
|
||||
you are being too clever.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Don't be clever.
|
||||
</p>
|
||||
|
||||
<h2>Happens Before</h2>
|
||||
|
||||
<p>
|
||||
@@ -69,8 +33,8 @@ Also, if <span class="event">e<sub>1</sub></span> does not happen before <span c
|
||||
after <span class="event">e<sub>2</sub></span>, then we say that <span class="event">e<sub>1</sub></span> and <span class="event">e<sub>2</sub></span> happen concurrently.
|
||||
</p>
|
||||
|
||||
<p class="rule">
|
||||
Within a single goroutine, the happens-before order is the
|
||||
<p>
|
||||
Within a single goroutine, the happens before order is the
|
||||
order expressed by the program.
|
||||
</p>
|
||||
|
||||
@@ -80,7 +44,7 @@ if both of the following hold:
|
||||
</p>
|
||||
|
||||
<ol>
|
||||
<li><span class="event">r</span> does not happen before <span class="event">w</span>.</li>
|
||||
<li><span class="event">w</span> happens before <span class="event">r</span>.</li>
|
||||
<li>There is no other write <span class="event">w'</span> to <code>v</code> that happens
|
||||
after <span class="event">w</span> but before <span class="event">r</span>.</li>
|
||||
</ol>
|
||||
@@ -130,9 +94,9 @@ unspecified order.
|
||||
<h3>Initialization</h3>
|
||||
|
||||
<p>
|
||||
Program initialization runs in a single goroutine,
|
||||
but that goroutine may create other goroutines,
|
||||
which run concurrently.
|
||||
Program initialization runs in a single goroutine and
|
||||
new goroutines created during initialization do not
|
||||
start running until initialization ends.
|
||||
</p>
|
||||
|
||||
<p class="rule">
|
||||
@@ -145,6 +109,11 @@ The start of the function <code>main.main</code> happens after
|
||||
all <code>init</code> functions have finished.
|
||||
</p>
|
||||
|
||||
<p class="rule">
|
||||
The execution of any goroutines created during <code>init</code>
|
||||
functions happens after all <code>init</code> functions have finished.
|
||||
</p>
|
||||
|
||||
<h3>Goroutine creation</h3>
|
||||
|
||||
<p class="rule">
|
||||
@@ -244,17 +213,6 @@ the corresponding receive on <code>c</code> completes, which happens before
|
||||
the <code>print</code>.
|
||||
</p>
|
||||
|
||||
<p class="rule">
|
||||
The closing of a channel happens before a receive that returns a zero value
|
||||
because the channel is closed.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
In the previous example, replacing
|
||||
<code>c <- 0</code> with <code>close(c)</code>
|
||||
yields a program with the same guaranteed behavior.
|
||||
</p>
|
||||
|
||||
<p class="rule">
|
||||
A receive from an unbuffered channel happens before
|
||||
the send on that channel completes.
|
||||
@@ -293,45 +251,10 @@ before the <code>print</code>.
|
||||
<p>
|
||||
If the channel were buffered (e.g., <code>c = make(chan int, 1)</code>)
|
||||
then the program would not be guaranteed to print
|
||||
<code>"hello, world"</code>. (It might print the empty string,
|
||||
crash, or do something else.)
|
||||
<code>"hello, world"</code>. (It might print the empty string;
|
||||
it cannot print <code>"goodbye, universe"</code>, nor can it crash.)
|
||||
</p>
|
||||
|
||||
<p class="rule">
|
||||
The <i>k</i>th receive on a channel with capacity <i>C</i> happens before the <i>k</i>+<i>C</i>th send from that channel completes.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
This rule generalizes the previous rule to buffered channels.
|
||||
It allows a counting semaphore to be modeled by a buffered channel:
|
||||
the number of items in the channel corresponds to the number of active uses,
|
||||
the capacity of the channel corresponds to the maximum number of simultaneous uses,
|
||||
sending an item acquires the semaphore, and receiving an item releases
|
||||
the semaphore.
|
||||
This is a common idiom for limiting concurrency.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
This program starts a goroutine for every entry in the work list, but the
|
||||
goroutines coordinate using the <code>limit</code> channel to ensure
|
||||
that at most three are running work functions at a time.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
var limit = make(chan int, 3)
|
||||
|
||||
func main() {
|
||||
for _, w := range work {
|
||||
go func() {
|
||||
limit <- 1
|
||||
w()
|
||||
<-limit
|
||||
}()
|
||||
}
|
||||
select{}
|
||||
}
|
||||
</pre>
|
||||
|
||||
<h3>Locks</h3>
|
||||
|
||||
<p>
|
||||
@@ -341,7 +264,7 @@ The <code>sync</code> package implements two lock data types,
|
||||
|
||||
<p class="rule">
|
||||
For any <code>sync.Mutex</code> or <code>sync.RWMutex</code> variable <code>l</code> and <i>n</i> < <i>m</i>,
|
||||
call <i>n</i> of <code>l.Unlock()</code> happens before call <i>m</i> of <code>l.Lock()</code> returns.
|
||||
the <i>n</i>'th call to <code>l.Unlock()</code> happens before the <i>m</i>'th call to <code>l.Lock()</code> returns.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
@@ -374,9 +297,9 @@ which happens before the <code>print</code>.
|
||||
|
||||
<p class="rule">
|
||||
For any call to <code>l.RLock</code> on a <code>sync.RWMutex</code> variable <code>l</code>,
|
||||
there is an <i>n</i> such that the <code>l.RLock</code> happens (returns) after call <i>n</i> to
|
||||
there is an <i>n</i> such that the <code>l.RLock</code> happens (returns) after the <i>n</i>'th call to
|
||||
<code>l.Unlock</code> and the matching <code>l.RUnlock</code> happens
|
||||
before call <i>n</i>+1 to <code>l.Lock</code>.
|
||||
before the <i>n</i>+1'th call to <code>l.Lock</code>.
|
||||
</p>
|
||||
|
||||
<h3>Once</h3>
|
||||
@@ -419,7 +342,7 @@ func twoprint() {
|
||||
|
||||
<p>
|
||||
calling <code>twoprint</code> causes <code>"hello, world"</code> to be printed twice.
|
||||
The first call to <code>doprint</code> runs <code>setup</code> once.
|
||||
The first call to <code>twoprint</code> runs <code>setup</code> once.
|
||||
</p>
|
||||
|
||||
<h2>Incorrect synchronization</h2>
|
||||
|
||||