[dev.typeparams] merge master (2f0da6d
) into dev.typeparams
This was a mostly clean merge, with the exception of codereview.cfg and changes in src/go/types. codereview.cfg for dev.typeparams is preserved in this CL. It should be deleted before merging back to master. The go/types changes were merged manually. For the most part this involved taking the union of patches, with the following exceptions: + declInfo.aliasPos is removed, as it is not necessary in dev.typeparams where we have access to the full TypeSpec. + Checker.overflow is updated to use the asBasic converter. + A TODO is added to errorcodes.go to ensure that go1.16 error codes are preserved. Change-Id: If9595196852e2163e27a9478df1e7b2c3704947d
158
CONTRIBUTORS
|
@ -30,6 +30,7 @@ Aaron Bieber <deftly@gmail.com>
|
||||||
Aaron Cannon <cannona@fireantproductions.com>
|
Aaron Cannon <cannona@fireantproductions.com>
|
||||||
Aaron France <aaron.l.france@gmail.com>
|
Aaron France <aaron.l.france@gmail.com>
|
||||||
Aaron Jacobs <jacobsa@google.com>
|
Aaron Jacobs <jacobsa@google.com>
|
||||||
|
Aaron Jensen <jensen.aaro@gmail.com>
|
||||||
Aaron Kemp <kemp.aaron@gmail.com>
|
Aaron Kemp <kemp.aaron@gmail.com>
|
||||||
Aaron Patterson <tenderlove@ruby-lang.org>
|
Aaron Patterson <tenderlove@ruby-lang.org>
|
||||||
Aaron Stein <aaronstein12@gmail.com>
|
Aaron Stein <aaronstein12@gmail.com>
|
||||||
|
@ -71,9 +72,11 @@ Ahmet Alp Balkan <ahmetb@google.com>
|
||||||
Ahmet Soormally <ahmet@mangomm.co.uk>
|
Ahmet Soormally <ahmet@mangomm.co.uk>
|
||||||
Ahmy Yulrizka <yulrizka@gmail.com>
|
Ahmy Yulrizka <yulrizka@gmail.com>
|
||||||
Ahsun Ahmed <ahmed.ahsun@gmail.com>
|
Ahsun Ahmed <ahmed.ahsun@gmail.com>
|
||||||
|
Aidan Coyle <packrat386@gmail.com>
|
||||||
Aiden Scandella <ai@uber.com>
|
Aiden Scandella <ai@uber.com>
|
||||||
Ainar Garipov <gugl.zadolbal@gmail.com>
|
Ainar Garipov <gugl.zadolbal@gmail.com>
|
||||||
Aishraj Dahal <aishraj@users.noreply.github.com>
|
Aishraj Dahal <aishraj@users.noreply.github.com>
|
||||||
|
Ajanthan Balachandran <balaajanthan@gmail.com>
|
||||||
Akhil Indurti <aindurti@gmail.com>
|
Akhil Indurti <aindurti@gmail.com>
|
||||||
Akihiro Suda <suda.kyoto@gmail.com>
|
Akihiro Suda <suda.kyoto@gmail.com>
|
||||||
Akshat Kumar <seed@mail.nanosouffle.net>
|
Akshat Kumar <seed@mail.nanosouffle.net>
|
||||||
|
@ -104,9 +107,11 @@ Alex Buchanan <buchanae@gmail.com>
|
||||||
Alex Carol <alex.carol.c@gmail.com>
|
Alex Carol <alex.carol.c@gmail.com>
|
||||||
Alex Gaynor <alex@alloy.us>
|
Alex Gaynor <alex@alloy.us>
|
||||||
Alex Harford <alex.harford@saucelabs.com>
|
Alex Harford <alex.harford@saucelabs.com>
|
||||||
|
Alex Hays <alex.hays@leftfieldlabs.com>
|
||||||
Alex Jin <toalexjin@gmail.com>
|
Alex Jin <toalexjin@gmail.com>
|
||||||
Alex Kohler <alexjohnkohler@gmail.com>
|
Alex Kohler <alexjohnkohler@gmail.com>
|
||||||
Alex Myasoedov <msoedov@gmail.com>
|
Alex Myasoedov <msoedov@gmail.com>
|
||||||
|
Alex Opie <amtopie@gmail.com>
|
||||||
Alex Plugaru <alex@plugaru.org> <alexandru.plugaru@gmail.com>
|
Alex Plugaru <alex@plugaru.org> <alexandru.plugaru@gmail.com>
|
||||||
Alex Schroeder <alex@gnu.org>
|
Alex Schroeder <alex@gnu.org>
|
||||||
Alex Sergeyev <abc@alexsergeyev.com>
|
Alex Sergeyev <abc@alexsergeyev.com>
|
||||||
|
@ -119,6 +124,7 @@ Alexander F Rødseth <alexander.rodseth@appeartv.com>
|
||||||
Alexander Greim <alexxx@iltempo.de>
|
Alexander Greim <alexxx@iltempo.de>
|
||||||
Alexander Guz <kalimatas@gmail.com>
|
Alexander Guz <kalimatas@gmail.com>
|
||||||
Alexander Kauer <alexander@affine.space>
|
Alexander Kauer <alexander@affine.space>
|
||||||
|
Alexander Klauer <Alexander.Klauer@googlemail.com>
|
||||||
Alexander Kucherenko <alxkchr@gmail.com>
|
Alexander Kucherenko <alxkchr@gmail.com>
|
||||||
Alexander Larsson <alexander.larsson@gmail.com>
|
Alexander Larsson <alexander.larsson@gmail.com>
|
||||||
Alexander Lourier <aml@rulezz.ru>
|
Alexander Lourier <aml@rulezz.ru>
|
||||||
|
@ -150,16 +156,19 @@ Alexey Naidonov <alexey.naidyonov@gmail.com>
|
||||||
Alexey Neganov <neganovalexey@gmail.com>
|
Alexey Neganov <neganovalexey@gmail.com>
|
||||||
Alexey Palazhchenko <alexey.palazhchenko@gmail.com>
|
Alexey Palazhchenko <alexey.palazhchenko@gmail.com>
|
||||||
Alexey Semenyuk <alexsemenyuk88@gmail.com>
|
Alexey Semenyuk <alexsemenyuk88@gmail.com>
|
||||||
|
Alexey Vilenskiy <bynovhack@gmail.com>
|
||||||
Alexis Hildebrandt <surryhill@gmail.com>
|
Alexis Hildebrandt <surryhill@gmail.com>
|
||||||
Alexis Hunt <lexer@google.com>
|
Alexis Hunt <lexer@google.com>
|
||||||
Alexis Imperial-Legrand <ail@google.com>
|
Alexis Imperial-Legrand <ail@google.com>
|
||||||
Ali Farooq <ali.farooq0@pm.me>
|
Ali Farooq <ali.farooq0@pm.me>
|
||||||
Ali Rizvi-Santiago <arizvisa@gmail.com>
|
Ali Rizvi-Santiago <arizvisa@gmail.com>
|
||||||
Aliaksandr Valialkin <valyala@gmail.com>
|
Aliaksandr Valialkin <valyala@gmail.com>
|
||||||
|
Alice Merrick <amerrick@google.com>
|
||||||
Alif Rachmawadi <subosito@gmail.com>
|
Alif Rachmawadi <subosito@gmail.com>
|
||||||
Allan Simon <allan.simon@supinfo.com>
|
Allan Simon <allan.simon@supinfo.com>
|
||||||
Allen Li <ayatane@google.com>
|
Allen Li <ayatane@google.com>
|
||||||
Alok Menghrajani <alok.menghrajani@gmail.com>
|
Alok Menghrajani <alok.menghrajani@gmail.com>
|
||||||
|
Alwin Doss <alwindoss84@gmail.com>
|
||||||
Aman Gupta <aman@tmm1.net>
|
Aman Gupta <aman@tmm1.net>
|
||||||
Amarjeet Anand <amarjeetanandsingh@gmail.com>
|
Amarjeet Anand <amarjeetanandsingh@gmail.com>
|
||||||
Amir Mohammad Saied <amir@gluegadget.com>
|
Amir Mohammad Saied <amir@gluegadget.com>
|
||||||
|
@ -168,6 +177,8 @@ Amrut Joshi <amrut.joshi@gmail.com>
|
||||||
An Long <aisk1988@gmail.com>
|
An Long <aisk1988@gmail.com>
|
||||||
An Xiao <hac@zju.edu.cn>
|
An Xiao <hac@zju.edu.cn>
|
||||||
Anand K. Mistry <anand@mistry.ninja>
|
Anand K. Mistry <anand@mistry.ninja>
|
||||||
|
Ananya Saxena <ananyasaxena1@gmail.com>
|
||||||
|
Anatol Pomozov <anatol.pomozov@gmail.com>
|
||||||
Anders Pearson <anders@columbia.edu>
|
Anders Pearson <anders@columbia.edu>
|
||||||
Anderson Queiroz <contato@andersonq.eti.br>
|
Anderson Queiroz <contato@andersonq.eti.br>
|
||||||
André Carvalho <asantostc@gmail.com>
|
André Carvalho <asantostc@gmail.com>
|
||||||
|
@ -199,6 +210,7 @@ Andrew G. Morgan <agm@google.com>
|
||||||
Andrew Gerrand <adg@golang.org>
|
Andrew Gerrand <adg@golang.org>
|
||||||
Andrew Harding <andrew@spacemonkey.com>
|
Andrew Harding <andrew@spacemonkey.com>
|
||||||
Andrew Jackura <ajackura@google.com>
|
Andrew Jackura <ajackura@google.com>
|
||||||
|
Andrew Kemm <andrewkemm@gmail.com>
|
||||||
Andrew Louis <alouis@digitalocean.com>
|
Andrew Louis <alouis@digitalocean.com>
|
||||||
Andrew Lutomirski <andy@luto.us>
|
Andrew Lutomirski <andy@luto.us>
|
||||||
Andrew Medvedev <andrew.y.medvedev@gmail.com>
|
Andrew Medvedev <andrew.y.medvedev@gmail.com>
|
||||||
|
@ -216,6 +228,7 @@ Andrew Werner <andrew@upthere.com> <awerner32@gmail.com>
|
||||||
Andrew Wilkins <axwalk@gmail.com>
|
Andrew Wilkins <axwalk@gmail.com>
|
||||||
Andrew Williams <williams.andrew@gmail.com>
|
Andrew Williams <williams.andrew@gmail.com>
|
||||||
Andrew Z Allen <me@andrewzallen.com>
|
Andrew Z Allen <me@andrewzallen.com>
|
||||||
|
Andrey Bokhanko <andreybokhanko@gmail.com>
|
||||||
Andrey Mirtchovski <mirtchovski@gmail.com>
|
Andrey Mirtchovski <mirtchovski@gmail.com>
|
||||||
Andrey Petrov <andrey.petrov@shazow.net>
|
Andrey Petrov <andrey.petrov@shazow.net>
|
||||||
Andrii Soldatenko <andrii.soldatenko@gmail.com>
|
Andrii Soldatenko <andrii.soldatenko@gmail.com>
|
||||||
|
@ -230,6 +243,7 @@ Andy Maloney <asmaloney@gmail.com>
|
||||||
Andy Pan <panjf2000@gmail.com>
|
Andy Pan <panjf2000@gmail.com>
|
||||||
Andy Walker <walkeraj@gmail.com>
|
Andy Walker <walkeraj@gmail.com>
|
||||||
Andy Wang <cbeuw.andy@gmail.com>
|
Andy Wang <cbeuw.andy@gmail.com>
|
||||||
|
Andy Williams <andy@andy.xyz>
|
||||||
Andzej Maciusovic <andzej.maciusovic@gmail.com>
|
Andzej Maciusovic <andzej.maciusovic@gmail.com>
|
||||||
Anfernee Yongkun Gui <anfernee.gui@gmail.com>
|
Anfernee Yongkun Gui <anfernee.gui@gmail.com>
|
||||||
Angelo Bulfone <mbulfone@gmail.com>
|
Angelo Bulfone <mbulfone@gmail.com>
|
||||||
|
@ -274,6 +288,7 @@ Arne Hormann <arnehormann@gmail.com>
|
||||||
Arnout Engelen <arnout@bzzt.net>
|
Arnout Engelen <arnout@bzzt.net>
|
||||||
Aron Nopanen <aron.nopanen@gmail.com>
|
Aron Nopanen <aron.nopanen@gmail.com>
|
||||||
Artem Alekseev <artem.alekseev@intel.com>
|
Artem Alekseev <artem.alekseev@intel.com>
|
||||||
|
Artem Khvastunov <artem.khvastunov@jetbrains.com>
|
||||||
Artem Kolin <artemkaxboy@gmail.com>
|
Artem Kolin <artemkaxboy@gmail.com>
|
||||||
Arthur Fabre <arthur@arthurfabre.com>
|
Arthur Fabre <arthur@arthurfabre.com>
|
||||||
Arthur Khashaev <arthur@khashaev.ru>
|
Arthur Khashaev <arthur@khashaev.ru>
|
||||||
|
@ -281,8 +296,10 @@ Artyom Pervukhin <artyom.pervukhin@gmail.com>
|
||||||
Arvindh Rajesh Tamilmani <art@a-30.net>
|
Arvindh Rajesh Tamilmani <art@a-30.net>
|
||||||
Ashish Gandhi <ag@ashishgandhi.org>
|
Ashish Gandhi <ag@ashishgandhi.org>
|
||||||
Asim Shankar <asimshankar@gmail.com>
|
Asim Shankar <asimshankar@gmail.com>
|
||||||
|
Assel Meher <asselmeher@gmail.com>
|
||||||
Atin Malaviya <amalaviy@akamai.com>
|
Atin Malaviya <amalaviy@akamai.com>
|
||||||
Ato Araki <ato.araki@gmail.com>
|
Ato Araki <ato.araki@gmail.com>
|
||||||
|
Atsushi Toyama <atsushi.tohyama.160.333@gmail.com>
|
||||||
Audrey Lim <audreylh@gmail.com>
|
Audrey Lim <audreylh@gmail.com>
|
||||||
Audrius Butkevicius <audrius.butkevicius@gmail.com>
|
Audrius Butkevicius <audrius.butkevicius@gmail.com>
|
||||||
Augusto Roman <aroman@gmail.com>
|
Augusto Roman <aroman@gmail.com>
|
||||||
|
@ -291,6 +308,7 @@ Aurélien Rainone <aurelien.rainone@gmail.com>
|
||||||
Aurélio A. Heckert <aurium@gmail.com>
|
Aurélio A. Heckert <aurium@gmail.com>
|
||||||
Austin Clements <austin@google.com> <aclements@csail.mit.edu>
|
Austin Clements <austin@google.com> <aclements@csail.mit.edu>
|
||||||
Avi Flax <avi@timehop.com>
|
Avi Flax <avi@timehop.com>
|
||||||
|
Aviv Klasquin Komissar <avivklas@gmail.com>
|
||||||
awaw fumin <awawfumin@gmail.com>
|
awaw fumin <awawfumin@gmail.com>
|
||||||
Awn Umar <awn@cryptolosophy.io>
|
Awn Umar <awn@cryptolosophy.io>
|
||||||
Axel Wagner <axel.wagner.hh@googlemail.com>
|
Axel Wagner <axel.wagner.hh@googlemail.com>
|
||||||
|
@ -298,6 +316,7 @@ Ayan George <ayan@ayan.net>
|
||||||
Ayanamist Yang <ayanamist@gmail.com>
|
Ayanamist Yang <ayanamist@gmail.com>
|
||||||
Ayke van Laethem <aykevanlaethem@gmail.com>
|
Ayke van Laethem <aykevanlaethem@gmail.com>
|
||||||
Aymerick Jéhanne <aymerick@jehanne.org>
|
Aymerick Jéhanne <aymerick@jehanne.org>
|
||||||
|
Ayzat Sadykov <ayzat.ziko.93@gmail.com>
|
||||||
Azat Kaumov <kaumov.a.r@gmail.com>
|
Azat Kaumov <kaumov.a.r@gmail.com>
|
||||||
Baiju Muthukadan <baiju.m.mail@gmail.com>
|
Baiju Muthukadan <baiju.m.mail@gmail.com>
|
||||||
Balaram Makam <bmakam.qdt@qualcommdatacenter.com>
|
Balaram Makam <bmakam.qdt@qualcommdatacenter.com>
|
||||||
|
@ -308,10 +327,12 @@ Bartosz Grzybowski <melkorm@gmail.com>
|
||||||
Bartosz Oler <brtsz@google.com>
|
Bartosz Oler <brtsz@google.com>
|
||||||
Bastian Ike <bastian.ike@gmail.com>
|
Bastian Ike <bastian.ike@gmail.com>
|
||||||
Ben Burkert <ben@benburkert.com>
|
Ben Burkert <ben@benburkert.com>
|
||||||
|
Ben Cartwright-Cox <Ben@Benjojo.co.uk>
|
||||||
Ben Eitzen <eitzenb@golang.org>
|
Ben Eitzen <eitzenb@golang.org>
|
||||||
Ben Fried <ben.fried@gmail.com>
|
Ben Fried <ben.fried@gmail.com>
|
||||||
Ben Haines <bhainesva@gmail.com>
|
Ben Haines <bhainesva@gmail.com>
|
||||||
Ben Hoyt <benhoyt@gmail.com>
|
Ben Hoyt <benhoyt@gmail.com>
|
||||||
|
Ben Kraft <benkraft@khanacademy.org>
|
||||||
Ben Laurie <ben@links.org> <benl@google.com>
|
Ben Laurie <ben@links.org> <benl@google.com>
|
||||||
Ben Lubar <ben.lubar@gmail.com>
|
Ben Lubar <ben.lubar@gmail.com>
|
||||||
Ben Lynn <benlynn@gmail.com>
|
Ben Lynn <benlynn@gmail.com>
|
||||||
|
@ -319,6 +340,7 @@ Ben Olive <sionide21@gmail.com>
|
||||||
Ben Schwartz <bemasc@google.com>
|
Ben Schwartz <bemasc@google.com>
|
||||||
Ben Shi <powerman1st@163.com>
|
Ben Shi <powerman1st@163.com>
|
||||||
Ben Toews <mastahyeti@gmail.com>
|
Ben Toews <mastahyeti@gmail.com>
|
||||||
|
Benjamin Barenblat <bbaren@google.com>
|
||||||
Benjamin Black <b@b3k.us>
|
Benjamin Black <b@b3k.us>
|
||||||
Benjamin Cable <cable.benjamin@gmail.com>
|
Benjamin Cable <cable.benjamin@gmail.com>
|
||||||
Benjamin Hsieh <tanookiben@users.noreply.github.com>
|
Benjamin Hsieh <tanookiben@users.noreply.github.com>
|
||||||
|
@ -356,6 +378,7 @@ Bobby Powers <bobbypowers@gmail.com>
|
||||||
Boqin Qin <bobbqqin@gmail.com>
|
Boqin Qin <bobbqqin@gmail.com>
|
||||||
Boris Nagaev <nagaev@google.com>
|
Boris Nagaev <nagaev@google.com>
|
||||||
Borja Clemente <borja.clemente@gmail.com>
|
Borja Clemente <borja.clemente@gmail.com>
|
||||||
|
Boshi Lian <bolian@microsoft.com>
|
||||||
Brad Burch <brad.burch@gmail.com>
|
Brad Burch <brad.burch@gmail.com>
|
||||||
Brad Erickson <bderickson@gmail.com>
|
Brad Erickson <bderickson@gmail.com>
|
||||||
Brad Fitzpatrick <bradfitz@golang.org> <bradfitz@gmail.com>
|
Brad Fitzpatrick <bradfitz@golang.org> <bradfitz@gmail.com>
|
||||||
|
@ -368,10 +391,12 @@ Bradford Lamson-Scribner <brad.lamson@gmail.com>
|
||||||
Bradley Falzon <brad@teambrad.net>
|
Bradley Falzon <brad@teambrad.net>
|
||||||
Brady Catherman <brady@gmail.com>
|
Brady Catherman <brady@gmail.com>
|
||||||
Brady Sullivan <brady@bsull.com>
|
Brady Sullivan <brady@bsull.com>
|
||||||
|
Branden J. Brown <zephyrtronium@gmail.com>
|
||||||
Brandon Bennett <bbennett@fb.com>
|
Brandon Bennett <bbennett@fb.com>
|
||||||
Brandon Gilmore <varz@google.com>
|
Brandon Gilmore <varz@google.com>
|
||||||
Brandon Philips <brandon@ifup.org>
|
Brandon Philips <brandon@ifup.org>
|
||||||
Brandon Ryan <bjryan19@gmail.com>
|
Brandon Ryan <bjryan19@gmail.com>
|
||||||
|
Brave Cow <rsr715@gmail.com>
|
||||||
Brayden Cloud <bcloud@google.com>
|
Brayden Cloud <bcloud@google.com>
|
||||||
Brendan Daniel Tracey <tracey.brendan@gmail.com>
|
Brendan Daniel Tracey <tracey.brendan@gmail.com>
|
||||||
Brendan O'Dea <bod@golang.org>
|
Brendan O'Dea <bod@golang.org>
|
||||||
|
@ -389,6 +414,7 @@ Brian Slesinsky <skybrian@google.com>
|
||||||
Brian Smith <ohohvi@gmail.com>
|
Brian Smith <ohohvi@gmail.com>
|
||||||
Brian Starke <brian.starke@gmail.com>
|
Brian Starke <brian.starke@gmail.com>
|
||||||
Bryan Alexander <Kozical@msn.com>
|
Bryan Alexander <Kozical@msn.com>
|
||||||
|
Bryan Boreham <bjboreham@gmail.com>
|
||||||
Bryan C. Mills <bcmills@google.com>
|
Bryan C. Mills <bcmills@google.com>
|
||||||
Bryan Chan <bryan.chan@ca.ibm.com>
|
Bryan Chan <bryan.chan@ca.ibm.com>
|
||||||
Bryan Ford <brynosaurus@gmail.com>
|
Bryan Ford <brynosaurus@gmail.com>
|
||||||
|
@ -407,6 +433,7 @@ Carl Mastrangelo <notcarl@google.com>
|
||||||
Carl Shapiro <cshapiro@google.com> <cshapiro@golang.org>
|
Carl Shapiro <cshapiro@google.com> <cshapiro@golang.org>
|
||||||
Carlisia Campos <carlisia@grokkingtech.io>
|
Carlisia Campos <carlisia@grokkingtech.io>
|
||||||
Carlo Alberto Ferraris <cafxx@strayorange.com>
|
Carlo Alberto Ferraris <cafxx@strayorange.com>
|
||||||
|
Carlos Alexandro Becker <caarlos0@gmail.com>
|
||||||
Carlos Amedee <carlos@golang.org>
|
Carlos Amedee <carlos@golang.org>
|
||||||
Carlos Castillo <cookieo9@gmail.com>
|
Carlos Castillo <cookieo9@gmail.com>
|
||||||
Carlos Cirello <uldericofilho@gmail.com>
|
Carlos Cirello <uldericofilho@gmail.com>
|
||||||
|
@ -422,6 +449,7 @@ Casey Callendrello <squeed@gmail.com>
|
||||||
Casey Marshall <casey.marshall@gmail.com>
|
Casey Marshall <casey.marshall@gmail.com>
|
||||||
Catalin Nicutar <cnicutar@google.com>
|
Catalin Nicutar <cnicutar@google.com>
|
||||||
Catalin Patulea <catalinp@google.com>
|
Catalin Patulea <catalinp@google.com>
|
||||||
|
Cathal O'Callaghan <cathalsocallaghan@gmail.com>
|
||||||
Cedric Staub <cs@squareup.com>
|
Cedric Staub <cs@squareup.com>
|
||||||
Cezar Sá Espinola <cezarsa@gmail.com>
|
Cezar Sá Espinola <cezarsa@gmail.com>
|
||||||
Chad Rosier <mrosier.qdt@qualcommdatacenter.com>
|
Chad Rosier <mrosier.qdt@qualcommdatacenter.com>
|
||||||
|
@ -434,10 +462,14 @@ Charles Kenney <charlesc.kenney@gmail.com>
|
||||||
Charles L. Dorian <cldorian@gmail.com>
|
Charles L. Dorian <cldorian@gmail.com>
|
||||||
Charles Lee <zombie.fml@gmail.com>
|
Charles Lee <zombie.fml@gmail.com>
|
||||||
Charles Weill <weill@google.com>
|
Charles Weill <weill@google.com>
|
||||||
|
Charlotte Brandhorst-Satzkorn <catzkorn@gmail.com>
|
||||||
Chauncy Cullitan <chauncyc@google.com>
|
Chauncy Cullitan <chauncyc@google.com>
|
||||||
|
Chen Zhidong <njutczd@gmail.com>
|
||||||
Chen Zhihan <energiehund@gmail.com>
|
Chen Zhihan <energiehund@gmail.com>
|
||||||
Cherry Zhang <cherryyz@google.com>
|
Cherry Zhang <cherryyz@google.com>
|
||||||
Chew Choon Keat <choonkeat@gmail.com>
|
Chew Choon Keat <choonkeat@gmail.com>
|
||||||
|
Chiawen Chen <golopot@gmail.com>
|
||||||
|
Chirag Sukhala <cchirag77@gmail.com>
|
||||||
Cholerae Hu <choleraehyq@gmail.com>
|
Cholerae Hu <choleraehyq@gmail.com>
|
||||||
Chotepud Teo <AlexRouSg@users.noreply.github.com>
|
Chotepud Teo <AlexRouSg@users.noreply.github.com>
|
||||||
Chris Ball <chris@printf.net>
|
Chris Ball <chris@printf.net>
|
||||||
|
@ -460,6 +492,8 @@ Chris Raynor <raynor@google.com>
|
||||||
Chris Roche <rodaine@gmail.com>
|
Chris Roche <rodaine@gmail.com>
|
||||||
Chris Smith <chrsmith@users.noreply.github.com>
|
Chris Smith <chrsmith@users.noreply.github.com>
|
||||||
Chris Stockton <chrisstocktonaz@gmail.com>
|
Chris Stockton <chrisstocktonaz@gmail.com>
|
||||||
|
Chris Taylor <taylorza@gmail.com>
|
||||||
|
Chris Waldon <christopher.waldon.dev@gmail.com>
|
||||||
Chris Zou <chriszou@ca.ibm.com>
|
Chris Zou <chriszou@ca.ibm.com>
|
||||||
Christian Alexander <christian@linux.com>
|
Christian Alexander <christian@linux.com>
|
||||||
Christian Couder <chriscool@tuxfamily.org>
|
Christian Couder <chriscool@tuxfamily.org>
|
||||||
|
@ -467,6 +501,7 @@ Christian Himpel <chressie@googlemail.com> <chressie@gmail.com>
|
||||||
Christian Muehlhaeuser <muesli@gmail.com>
|
Christian Muehlhaeuser <muesli@gmail.com>
|
||||||
Christian Pellegrin <chri@evolware.org>
|
Christian Pellegrin <chri@evolware.org>
|
||||||
Christian R. Petrin <christianpetrin@gmail.com>
|
Christian R. Petrin <christianpetrin@gmail.com>
|
||||||
|
Christian Svensson <blue@cmd.nu>
|
||||||
Christine Hansmann <chhansmann@gmail.com>
|
Christine Hansmann <chhansmann@gmail.com>
|
||||||
Christoffer Buchholz <christoffer.buchholz@gmail.com>
|
Christoffer Buchholz <christoffer.buchholz@gmail.com>
|
||||||
Christoph Blecker <admin@toph.ca>
|
Christoph Blecker <admin@toph.ca>
|
||||||
|
@ -474,6 +509,7 @@ Christoph Hack <christoph@tux21b.org>
|
||||||
Christopher Cahoon <chris.cahoon@gmail.com>
|
Christopher Cahoon <chris.cahoon@gmail.com>
|
||||||
Christopher Guiney <chris@guiney.net>
|
Christopher Guiney <chris@guiney.net>
|
||||||
Christopher Henderson <chris@chenderson.org>
|
Christopher Henderson <chris@chenderson.org>
|
||||||
|
Christopher Hlubek <christopher.hlubek@networkteam.com>
|
||||||
Christopher Koch <chrisko@google.com>
|
Christopher Koch <chrisko@google.com>
|
||||||
Christopher Loessl <cloessl+github@gmail.com>
|
Christopher Loessl <cloessl+github@gmail.com>
|
||||||
Christopher Nelson <nadiasvertex@gmail.com>
|
Christopher Nelson <nadiasvertex@gmail.com>
|
||||||
|
@ -506,7 +542,10 @@ Costin Chirvasuta <ctin@google.com>
|
||||||
Craig Citro <craigcitro@google.com>
|
Craig Citro <craigcitro@google.com>
|
||||||
Cristian Staretu <unclejacksons@gmail.com>
|
Cristian Staretu <unclejacksons@gmail.com>
|
||||||
Cuihtlauac ALVARADO <cuihtlauac.alvarado@orange.com>
|
Cuihtlauac ALVARADO <cuihtlauac.alvarado@orange.com>
|
||||||
|
Cuong Manh Le <cuong@orijtech.com>
|
||||||
|
Curtis La Graff <curtis@lagraff.me>
|
||||||
Cyrill Schumacher <cyrill@schumacher.fm>
|
Cyrill Schumacher <cyrill@schumacher.fm>
|
||||||
|
Dai Jie <gzdaijie@gmail.com>
|
||||||
Daisuke Fujita <dtanshi45@gmail.com>
|
Daisuke Fujita <dtanshi45@gmail.com>
|
||||||
Daisuke Suzuki <daisuzu@gmail.com>
|
Daisuke Suzuki <daisuzu@gmail.com>
|
||||||
Daker Fernandes Pinheiro <daker.fernandes.pinheiro@intel.com>
|
Daker Fernandes Pinheiro <daker.fernandes.pinheiro@intel.com>
|
||||||
|
@ -525,12 +564,14 @@ Dan Peterson <dpiddy@gmail.com>
|
||||||
Dan Pupius <dan@medium.com>
|
Dan Pupius <dan@medium.com>
|
||||||
Dan Scales <danscales@google.com>
|
Dan Scales <danscales@google.com>
|
||||||
Dan Sinclair <dan.sinclair@gmail.com>
|
Dan Sinclair <dan.sinclair@gmail.com>
|
||||||
|
Daniel Cohen <dcohen@gatech.edu>
|
||||||
Daniel Cormier <danielc@knowbe4.com>
|
Daniel Cormier <danielc@knowbe4.com>
|
||||||
Daniël de Kok <me@danieldk.eu>
|
Daniël de Kok <me@danieldk.eu>
|
||||||
Daniel Fleischman <danielfleischman@gmail.com>
|
Daniel Fleischman <danielfleischman@gmail.com>
|
||||||
Daniel Ingram <ingramds@appstate.edu>
|
Daniel Ingram <ingramds@appstate.edu>
|
||||||
Daniel Johansson <dajo2002@gmail.com>
|
Daniel Johansson <dajo2002@gmail.com>
|
||||||
Daniel Kerwin <d.kerwin@gini.net>
|
Daniel Kerwin <d.kerwin@gini.net>
|
||||||
|
Daniel Kessler <dkess@google.com>
|
||||||
Daniel Krech <eikeon@eikeon.com>
|
Daniel Krech <eikeon@eikeon.com>
|
||||||
Daniel Kumor <rdkumor@gmail.com>
|
Daniel Kumor <rdkumor@gmail.com>
|
||||||
Daniel Langner <s8572327@gmail.com>
|
Daniel Langner <s8572327@gmail.com>
|
||||||
|
@ -538,10 +579,12 @@ Daniel Lidén <daniel.liden.87@gmail.com>
|
||||||
Daniel Lublin <daniel@lublin.se>
|
Daniel Lublin <daniel@lublin.se>
|
||||||
Daniel Mangum <georgedanielmangum@gmail.com>
|
Daniel Mangum <georgedanielmangum@gmail.com>
|
||||||
Daniel Martí <mvdan@mvdan.cc>
|
Daniel Martí <mvdan@mvdan.cc>
|
||||||
|
Daniel McCarney <cpu@letsencrypt.org>
|
||||||
Daniel Morsing <daniel.morsing@gmail.com>
|
Daniel Morsing <daniel.morsing@gmail.com>
|
||||||
Daniel Nadasi <dnadasi@google.com>
|
Daniel Nadasi <dnadasi@google.com>
|
||||||
Daniel Nephin <dnephin@gmail.com>
|
Daniel Nephin <dnephin@gmail.com>
|
||||||
Daniel Ortiz Pereira da Silva <daniel.particular@gmail.com>
|
Daniel Ortiz Pereira da Silva <daniel.particular@gmail.com>
|
||||||
|
Daniel S. Fava <danielsfava@gmail.com>
|
||||||
Daniel Skinner <daniel@dasa.cc>
|
Daniel Skinner <daniel@dasa.cc>
|
||||||
Daniel Speichert <daniel@speichert.pl>
|
Daniel Speichert <daniel@speichert.pl>
|
||||||
Daniel Theophanes <kardianos@gmail.com>
|
Daniel Theophanes <kardianos@gmail.com>
|
||||||
|
@ -563,6 +606,7 @@ Dave Cheney <dave@cheney.net>
|
||||||
Dave Day <djd@golang.org>
|
Dave Day <djd@golang.org>
|
||||||
Dave Grijalva <dgrijalva@ngmoco.com>
|
Dave Grijalva <dgrijalva@ngmoco.com>
|
||||||
Dave MacFarlane <driusan@gmail.com>
|
Dave MacFarlane <driusan@gmail.com>
|
||||||
|
Dave Pifke <dave@pifke.org>
|
||||||
Dave Russell <forfuncsake@gmail.com>
|
Dave Russell <forfuncsake@gmail.com>
|
||||||
David Anderson <danderson@google.com>
|
David Anderson <danderson@google.com>
|
||||||
David Barnett <dbarnett@google.com>
|
David Barnett <dbarnett@google.com>
|
||||||
|
@ -593,6 +637,7 @@ David McLeish <davemc@google.com>
|
||||||
David Ndungu <dnjuguna@gmail.com>
|
David Ndungu <dnjuguna@gmail.com>
|
||||||
David NewHamlet <david@newhamlet.com>
|
David NewHamlet <david@newhamlet.com>
|
||||||
David Presotto <presotto@gmail.com>
|
David Presotto <presotto@gmail.com>
|
||||||
|
David Qu <davidqu12345@gmail.com>
|
||||||
David R. Jenni <david.r.jenni@gmail.com>
|
David R. Jenni <david.r.jenni@gmail.com>
|
||||||
David Sansome <me@davidsansome.com>
|
David Sansome <me@davidsansome.com>
|
||||||
David Stainton <dstainton415@gmail.com>
|
David Stainton <dstainton415@gmail.com>
|
||||||
|
@ -642,6 +687,7 @@ Diwaker Gupta <diwakergupta@gmail.com>
|
||||||
Dmitri Goutnik <dgoutnik@gmail.com>
|
Dmitri Goutnik <dgoutnik@gmail.com>
|
||||||
Dmitri Popov <operator@cv.dp-net.com>
|
Dmitri Popov <operator@cv.dp-net.com>
|
||||||
Dmitri Shuralyov <dmitshur@golang.org> <dmitri@shuralyov.com>
|
Dmitri Shuralyov <dmitshur@golang.org> <dmitri@shuralyov.com>
|
||||||
|
Dmitrii Okunev <xaionaro@gmail.com>
|
||||||
Dmitriy Cherchenko <dcherchenko@gmail.com>
|
Dmitriy Cherchenko <dcherchenko@gmail.com>
|
||||||
Dmitriy Dudkin <dudkin.dmitriy@gmail.com>
|
Dmitriy Dudkin <dudkin.dmitriy@gmail.com>
|
||||||
Dmitriy Shelenin <deemok@googlemail.com> <deemok@gmail.com>
|
Dmitriy Shelenin <deemok@googlemail.com> <deemok@gmail.com>
|
||||||
|
@ -655,6 +701,7 @@ Dmitry Yakunin <nonamezeil@gmail.com>
|
||||||
Doga Fincan <doga@icloud.com>
|
Doga Fincan <doga@icloud.com>
|
||||||
Domas Tamašauskas <puerdomus@gmail.com>
|
Domas Tamašauskas <puerdomus@gmail.com>
|
||||||
Domen Ipavec <domen@ipavec.net>
|
Domen Ipavec <domen@ipavec.net>
|
||||||
|
Dominic Della Valle <ddvpublic@Gmail.com>
|
||||||
Dominic Green <dominicgreen1@gmail.com>
|
Dominic Green <dominicgreen1@gmail.com>
|
||||||
Dominik Honnef <dominik.honnef@gmail.com>
|
Dominik Honnef <dominik.honnef@gmail.com>
|
||||||
Dominik Vogt <vogt@linux.vnet.ibm.com>
|
Dominik Vogt <vogt@linux.vnet.ibm.com>
|
||||||
|
@ -696,6 +743,7 @@ Elias Naur <mail@eliasnaur.com> <elias.naur@gmail.com>
|
||||||
Elliot Morrison-Reed <elliotmr@gmail.com>
|
Elliot Morrison-Reed <elliotmr@gmail.com>
|
||||||
Ellison Leão <ellisonleao@gmail.com>
|
Ellison Leão <ellisonleao@gmail.com>
|
||||||
Emerson Lin <linyintor@gmail.com>
|
Emerson Lin <linyintor@gmail.com>
|
||||||
|
Emil Bektimirov <lefelys@gmail.com>
|
||||||
Emil Hessman <emil@hessman.se>
|
Emil Hessman <emil@hessman.se>
|
||||||
Emil Mursalimov <mursalimovemeel@gmail.com>
|
Emil Mursalimov <mursalimovemeel@gmail.com>
|
||||||
Emilien Kenler <hello@emilienkenler.com>
|
Emilien Kenler <hello@emilienkenler.com>
|
||||||
|
@ -760,6 +808,7 @@ Fatih Arslan <fatih@arslan.io>
|
||||||
Fazal Majid <majid@apsalar.com>
|
Fazal Majid <majid@apsalar.com>
|
||||||
Fazlul Shahriar <fshahriar@gmail.com>
|
Fazlul Shahriar <fshahriar@gmail.com>
|
||||||
Federico Bond <federicobond@gmail.com>
|
Federico Bond <federicobond@gmail.com>
|
||||||
|
Federico Guerinoni <guerinoni.federico@gmail.com>
|
||||||
Federico Simoncelli <fsimonce@redhat.com>
|
Federico Simoncelli <fsimonce@redhat.com>
|
||||||
Fedor Indutny <fedor@indutny.com>
|
Fedor Indutny <fedor@indutny.com>
|
||||||
Fedor Korotkiy <dartslon@gmail.com>
|
Fedor Korotkiy <dartslon@gmail.com>
|
||||||
|
@ -781,6 +830,7 @@ Florin Patan <florinpatan@gmail.com>
|
||||||
Folke Behrens <folke@google.com>
|
Folke Behrens <folke@google.com>
|
||||||
Ford Hurley <ford.hurley@gmail.com>
|
Ford Hurley <ford.hurley@gmail.com>
|
||||||
Francesc Campoy <campoy@golang.org>
|
Francesc Campoy <campoy@golang.org>
|
||||||
|
Francesco Guardiani <francescoguard@gmail.com>
|
||||||
Francesco Renzi <rentziass@gmail.com>
|
Francesco Renzi <rentziass@gmail.com>
|
||||||
Francisco Claude <fclaude@recoded.cl>
|
Francisco Claude <fclaude@recoded.cl>
|
||||||
Francisco Rojas <francisco.rojas.gallegos@gmail.com>
|
Francisco Rojas <francisco.rojas.gallegos@gmail.com>
|
||||||
|
@ -811,8 +861,10 @@ Gabriel Russell <gabriel.russell@gmail.com>
|
||||||
Gareth Paul Jones <gpj@foursquare.com>
|
Gareth Paul Jones <gpj@foursquare.com>
|
||||||
Garret Kelly <gdk@google.com>
|
Garret Kelly <gdk@google.com>
|
||||||
Garrick Evans <garrick@google.com>
|
Garrick Evans <garrick@google.com>
|
||||||
|
Garry McNulty <garrmcnu@gmail.com>
|
||||||
Gary Burd <gary@beagledreams.com> <gary.burd@gmail.com>
|
Gary Burd <gary@beagledreams.com> <gary.burd@gmail.com>
|
||||||
Gary Elliott <garyelliott@google.com>
|
Gary Elliott <garyelliott@google.com>
|
||||||
|
Gaurav Singh <gaurav1086@gmail.com>
|
||||||
Gaurish Sharma <contact@gaurishsharma.com>
|
Gaurish Sharma <contact@gaurishsharma.com>
|
||||||
Gautham Thambidorai <gautham.dorai@gmail.com>
|
Gautham Thambidorai <gautham.dorai@gmail.com>
|
||||||
Gauthier Jolly <gauthier.jolly@gmail.com>
|
Gauthier Jolly <gauthier.jolly@gmail.com>
|
||||||
|
@ -827,6 +879,7 @@ Georg Reinke <guelfey@gmail.com>
|
||||||
George Gkirtsou <ggirtsou@gmail.com>
|
George Gkirtsou <ggirtsou@gmail.com>
|
||||||
George Hartzell <hartzell@alerce.com>
|
George Hartzell <hartzell@alerce.com>
|
||||||
George Shammas <george@shamm.as> <georgyo@gmail.com>
|
George Shammas <george@shamm.as> <georgyo@gmail.com>
|
||||||
|
George Tsilias <tsiliasg@gmail.com>
|
||||||
Gerasimos (Makis) Maropoulos <kataras2006@hotmail.com>
|
Gerasimos (Makis) Maropoulos <kataras2006@hotmail.com>
|
||||||
Gerasimos Dimitriadis <gedimitr@gmail.com>
|
Gerasimos Dimitriadis <gedimitr@gmail.com>
|
||||||
Gergely Brautigam <skarlso777@gmail.com>
|
Gergely Brautigam <skarlso777@gmail.com>
|
||||||
|
@ -862,6 +915,7 @@ GitHub User @frennkie (6499251) <mail@rhab.de>
|
||||||
GitHub User @geedchin (11672310) <geedchin@gmail.com>
|
GitHub User @geedchin (11672310) <geedchin@gmail.com>
|
||||||
GitHub User @GrigoriyMikhalkin (3637857) <grigoriymikhalkin@gmail.com>
|
GitHub User @GrigoriyMikhalkin (3637857) <grigoriymikhalkin@gmail.com>
|
||||||
GitHub User @hengwu0 (41297446) <41297446+hengwu0@users.noreply.github.com>
|
GitHub User @hengwu0 (41297446) <41297446+hengwu0@users.noreply.github.com>
|
||||||
|
GitHub User @hitzhangjie (3725760) <hit.zhangjie@gmail.com>
|
||||||
GitHub User @itchyny (375258) <itchyny@hatena.ne.jp>
|
GitHub User @itchyny (375258) <itchyny@hatena.ne.jp>
|
||||||
GitHub User @jinmiaoluo (39730824) <jinmiaoluo@icloud.com>
|
GitHub User @jinmiaoluo (39730824) <jinmiaoluo@icloud.com>
|
||||||
GitHub User @jopbrown (6345470) <msshane2008@gmail.com>
|
GitHub User @jopbrown (6345470) <msshane2008@gmail.com>
|
||||||
|
@ -873,6 +927,7 @@ GitHub User @LotusFenn (13775899) <fenn.lotus@gmail.com>
|
||||||
GitHub User @ly303550688 (11519839) <yang.liu636@gmail.com>
|
GitHub User @ly303550688 (11519839) <yang.liu636@gmail.com>
|
||||||
GitHub User @madiganz (18340029) <zacharywmadigan@gmail.com>
|
GitHub User @madiganz (18340029) <zacharywmadigan@gmail.com>
|
||||||
GitHub User @maltalex (10195391) <code@bit48.net>
|
GitHub User @maltalex (10195391) <code@bit48.net>
|
||||||
|
GitHub User @markruler (38225900) <csu0414@gmail.com>
|
||||||
GitHub User @Matts966 (28551465) <Matts966@users.noreply.github.com>
|
GitHub User @Matts966 (28551465) <Matts966@users.noreply.github.com>
|
||||||
GitHub User @micnncim (21333876) <micnncim@gmail.com>
|
GitHub User @micnncim (21333876) <micnncim@gmail.com>
|
||||||
GitHub User @mkishere (224617) <224617+mkishere@users.noreply.github.com>
|
GitHub User @mkishere (224617) <224617+mkishere@users.noreply.github.com>
|
||||||
|
@ -886,6 +941,8 @@ GitHub User @ramenjuniti (32011829) <ramenjuniti@gmail.com>
|
||||||
GitHub User @saitarunreddy (21041941) <saitarunreddypalla@gmail.com>
|
GitHub User @saitarunreddy (21041941) <saitarunreddypalla@gmail.com>
|
||||||
GitHub User @shogo-ma (9860598) <Choroma194@gmail.com>
|
GitHub User @shogo-ma (9860598) <Choroma194@gmail.com>
|
||||||
GitHub User @skanehira (7888591) <sho19921005@gmail.com>
|
GitHub User @skanehira (7888591) <sho19921005@gmail.com>
|
||||||
|
GitHub User @soolaugust (10558124) <soolaugust@gmail.com>
|
||||||
|
GitHub User @surechen (7249331) <surechen17@gmail.com>
|
||||||
GitHub User @tatsumack (4510569) <tatsu.mack@gmail.com>
|
GitHub User @tatsumack (4510569) <tatsu.mack@gmail.com>
|
||||||
GitHub User @tell-k (26263) <ffk2005@gmail.com>
|
GitHub User @tell-k (26263) <ffk2005@gmail.com>
|
||||||
GitHub User @tennashi (10219626) <tennashio@gmail.com>
|
GitHub User @tennashi (10219626) <tennashio@gmail.com>
|
||||||
|
@ -908,6 +965,7 @@ Gordon Tyler <gordon@doxxx.net>
|
||||||
Graham King <graham4king@gmail.com>
|
Graham King <graham4king@gmail.com>
|
||||||
Graham Miller <graham.miller@gmail.com>
|
Graham Miller <graham.miller@gmail.com>
|
||||||
Grant Griffiths <ggp493@gmail.com>
|
Grant Griffiths <ggp493@gmail.com>
|
||||||
|
Green Lightning <GreenLightning.git@googlemail.com>
|
||||||
Greg Poirier <greg.istehbest@gmail.com>
|
Greg Poirier <greg.istehbest@gmail.com>
|
||||||
Greg Steuck <gnezdo+github@google.com>
|
Greg Steuck <gnezdo+github@google.com>
|
||||||
Greg Thelen <gthelen@google.com>
|
Greg Thelen <gthelen@google.com>
|
||||||
|
@ -920,6 +978,7 @@ Guilherme Garnier <guilherme.garnier@gmail.com>
|
||||||
Guilherme Goncalves <guilhermeaugustosg@gmail.com>
|
Guilherme Goncalves <guilhermeaugustosg@gmail.com>
|
||||||
Guilherme Rezende <guilhermebr@gmail.com>
|
Guilherme Rezende <guilhermebr@gmail.com>
|
||||||
Guillaume J. Charmes <guillaume@charmes.net>
|
Guillaume J. Charmes <guillaume@charmes.net>
|
||||||
|
Guillaume Sottas <guillaumesottas@gmail.com>
|
||||||
Günther Noack <gnoack@google.com>
|
Günther Noack <gnoack@google.com>
|
||||||
Guobiao Mei <meiguobiao@gmail.com>
|
Guobiao Mei <meiguobiao@gmail.com>
|
||||||
Guoliang Wang <iamwgliang@gmail.com>
|
Guoliang Wang <iamwgliang@gmail.com>
|
||||||
|
@ -936,6 +995,8 @@ HAMANO Tsukasa <hamano@osstech.co.jp>
|
||||||
Han-Wen Nienhuys <hanwen@google.com>
|
Han-Wen Nienhuys <hanwen@google.com>
|
||||||
Hang Qian <hangqian90@gmail.com>
|
Hang Qian <hangqian90@gmail.com>
|
||||||
Hanjun Kim <hallazzang@gmail.com>
|
Hanjun Kim <hallazzang@gmail.com>
|
||||||
|
Hanlin Shi <shihanlin9@gmail.com>
|
||||||
|
Haoran Luo <haoran.luo@chaitin.com>
|
||||||
Haosdent Huang <haosdent@gmail.com>
|
Haosdent Huang <haosdent@gmail.com>
|
||||||
Harald Nordgren <haraldnordgren@gmail.com>
|
Harald Nordgren <haraldnordgren@gmail.com>
|
||||||
Hari haran <hariharan.uno@gmail.com>
|
Hari haran <hariharan.uno@gmail.com>
|
||||||
|
@ -950,9 +1011,11 @@ Håvard Haugen <havard.haugen@gmail.com>
|
||||||
He Liu <liulonnie@gmail.com>
|
He Liu <liulonnie@gmail.com>
|
||||||
Hector Chu <hectorchu@gmail.com>
|
Hector Chu <hectorchu@gmail.com>
|
||||||
Hector Martin Cantero <hector@marcansoft.com>
|
Hector Martin Cantero <hector@marcansoft.com>
|
||||||
|
Hein Khant Zaw <heinkhantzaw1@gmail.com>
|
||||||
Henning Schmiedehausen <henning@schmiedehausen.org>
|
Henning Schmiedehausen <henning@schmiedehausen.org>
|
||||||
Henrik Edwards <henrik.edwards@gmail.com>
|
Henrik Edwards <henrik.edwards@gmail.com>
|
||||||
Henrik Hodne <henrik@hodne.io>
|
Henrik Hodne <henrik@hodne.io>
|
||||||
|
Henrique Vicente <henriquevicente@gmail.com>
|
||||||
Henry Adi Sumarto <henry.adisumarto@gmail.com>
|
Henry Adi Sumarto <henry.adisumarto@gmail.com>
|
||||||
Henry Bubert <google@mindeco.de>
|
Henry Bubert <google@mindeco.de>
|
||||||
Henry Chang <mr.changyuheng@gmail.com>
|
Henry Chang <mr.changyuheng@gmail.com>
|
||||||
|
@ -969,6 +1032,7 @@ Hironao OTSUBO <motemen@gmail.com>
|
||||||
Hiroshi Ioka <hirochachacha@gmail.com>
|
Hiroshi Ioka <hirochachacha@gmail.com>
|
||||||
Hitoshi Mitake <mitake.hitoshi@gmail.com>
|
Hitoshi Mitake <mitake.hitoshi@gmail.com>
|
||||||
Holden Huang <ttyh061@gmail.com>
|
Holden Huang <ttyh061@gmail.com>
|
||||||
|
Songlin Jiang <hollowman@hollowman.ml>
|
||||||
Hong Ruiqi <hongruiqi@gmail.com>
|
Hong Ruiqi <hongruiqi@gmail.com>
|
||||||
Hongfei Tan <feilengcui008@gmail.com>
|
Hongfei Tan <feilengcui008@gmail.com>
|
||||||
Horacio Duran <horacio.duran@gmail.com>
|
Horacio Duran <horacio.duran@gmail.com>
|
||||||
|
@ -990,6 +1054,7 @@ Ian Haken <ihaken@netflix.com>
|
||||||
Ian Kent <iankent85@gmail.com>
|
Ian Kent <iankent85@gmail.com>
|
||||||
Ian Lance Taylor <iant@golang.org>
|
Ian Lance Taylor <iant@golang.org>
|
||||||
Ian Leue <ian@appboy.com>
|
Ian Leue <ian@appboy.com>
|
||||||
|
Ian Tay <iantay@google.com>
|
||||||
Ian Zapolsky <ianzapolsky@gmail.com>
|
Ian Zapolsky <ianzapolsky@gmail.com>
|
||||||
Ibrahim AshShohail <ibra.sho@gmail.com>
|
Ibrahim AshShohail <ibra.sho@gmail.com>
|
||||||
Icarus Sparry <golang@icarus.freeuk.com>
|
Icarus Sparry <golang@icarus.freeuk.com>
|
||||||
|
@ -997,9 +1062,11 @@ Iccha Sethi <icchasethi@gmail.com>
|
||||||
Idora Shinatose <idora.shinatose@gmail.com>
|
Idora Shinatose <idora.shinatose@gmail.com>
|
||||||
Ignacio Hagopian <jsign.uy@gmail.com>
|
Ignacio Hagopian <jsign.uy@gmail.com>
|
||||||
Igor Bernstein <igorbernstein@google.com>
|
Igor Bernstein <igorbernstein@google.com>
|
||||||
|
Igor Bolotnikov <igor.v.bolotnikov@gmail.com>
|
||||||
Igor Dolzhikov <bluesriverz@gmail.com>
|
Igor Dolzhikov <bluesriverz@gmail.com>
|
||||||
Igor Vashyst <ivashyst@gmail.com>
|
Igor Vashyst <ivashyst@gmail.com>
|
||||||
Igor Zhilianin <igor.zhilianin@gmail.com>
|
Igor Zhilianin <igor.zhilianin@gmail.com>
|
||||||
|
Ikko Ashimine <eltociear@gmail.com>
|
||||||
Illya Yalovyy <yalovoy@gmail.com>
|
Illya Yalovyy <yalovoy@gmail.com>
|
||||||
Ilya Sinelnikov <sidhmangh@gmail.com>
|
Ilya Sinelnikov <sidhmangh@gmail.com>
|
||||||
Ilya Tocar <ilya.tocar@intel.com>
|
Ilya Tocar <ilya.tocar@intel.com>
|
||||||
|
@ -1037,6 +1104,7 @@ Jacob Blain Christen <dweomer5@gmail.com>
|
||||||
Jacob H. Haven <jacob@cloudflare.com>
|
Jacob H. Haven <jacob@cloudflare.com>
|
||||||
Jacob Hoffman-Andrews <github@hoffman-andrews.com>
|
Jacob Hoffman-Andrews <github@hoffman-andrews.com>
|
||||||
Jacob Walker <jacobwalker0814@gmail.com>
|
Jacob Walker <jacobwalker0814@gmail.com>
|
||||||
|
Jaden Teng <long.asyn@gmail.com>
|
||||||
Jae Kwon <jae@tendermint.com>
|
Jae Kwon <jae@tendermint.com>
|
||||||
Jake B <doogie1012@gmail.com>
|
Jake B <doogie1012@gmail.com>
|
||||||
Jakob Borg <jakob@nym.se>
|
Jakob Borg <jakob@nym.se>
|
||||||
|
@ -1044,6 +1112,7 @@ Jakob Weisblat <jakobw@mit.edu>
|
||||||
Jakub Čajka <jcajka@redhat.com>
|
Jakub Čajka <jcajka@redhat.com>
|
||||||
Jakub Kaczmarzyk <jakubk@mit.edu>
|
Jakub Kaczmarzyk <jakubk@mit.edu>
|
||||||
Jakub Ryszard Czarnowicz <j.czarnowicz@gmail.com>
|
Jakub Ryszard Czarnowicz <j.czarnowicz@gmail.com>
|
||||||
|
Jakub Warczarek <jakub.warczarek@gmail.com>
|
||||||
Jamal Carvalho <jamal.a.carvalho@gmail.com>
|
Jamal Carvalho <jamal.a.carvalho@gmail.com>
|
||||||
James Aguilar <jaguilar@google.com>
|
James Aguilar <jaguilar@google.com>
|
||||||
James Bardin <j.bardin@gmail.com>
|
James Bardin <j.bardin@gmail.com>
|
||||||
|
@ -1056,9 +1125,11 @@ James Eady <jmeady@google.com>
|
||||||
James Fysh <james.fysh@gmail.com>
|
James Fysh <james.fysh@gmail.com>
|
||||||
James Gray <james@james4k.com>
|
James Gray <james@james4k.com>
|
||||||
James Hartig <fastest963@gmail.com>
|
James Hartig <fastest963@gmail.com>
|
||||||
|
James Kasten <jdkasten@google.com>
|
||||||
James Lawrence <jljatone@gmail.com>
|
James Lawrence <jljatone@gmail.com>
|
||||||
James Meneghello <rawrz0r@gmail.com>
|
James Meneghello <rawrz0r@gmail.com>
|
||||||
James Myers <jfmyers9@gmail.com>
|
James Myers <jfmyers9@gmail.com>
|
||||||
|
James Naftel <james.naftel@gmail.com>
|
||||||
James Neve <jamesoneve@gmail.com>
|
James Neve <jamesoneve@gmail.com>
|
||||||
James Nugent <james@jen20.com>
|
James Nugent <james@jen20.com>
|
||||||
James P. Cooper <jamespcooper@gmail.com>
|
James P. Cooper <jamespcooper@gmail.com>
|
||||||
|
@ -1108,6 +1179,7 @@ Javier Kohen <jkohen@google.com>
|
||||||
Javier Revillas <jrevillas@massivedynamic.io>
|
Javier Revillas <jrevillas@massivedynamic.io>
|
||||||
Javier Segura <javism@gmail.com>
|
Javier Segura <javism@gmail.com>
|
||||||
Jay Conrod <jayconrod@google.com>
|
Jay Conrod <jayconrod@google.com>
|
||||||
|
Jay Lee <BusyJayLee@gmail.com>
|
||||||
Jay Taylor <outtatime@gmail.com>
|
Jay Taylor <outtatime@gmail.com>
|
||||||
Jay Weisskopf <jay@jayschwa.net>
|
Jay Weisskopf <jay@jayschwa.net>
|
||||||
Jean de Klerk <deklerk@google.com>
|
Jean de Klerk <deklerk@google.com>
|
||||||
|
@ -1140,14 +1212,17 @@ Jeremy Jay <jeremy@pbnjay.com>
|
||||||
Jeremy Schlatter <jeremy.schlatter@gmail.com>
|
Jeremy Schlatter <jeremy.schlatter@gmail.com>
|
||||||
Jeroen Bobbeldijk <jerbob92@gmail.com>
|
Jeroen Bobbeldijk <jerbob92@gmail.com>
|
||||||
Jeroen Simonetti <jeroen@simonetti.nl>
|
Jeroen Simonetti <jeroen@simonetti.nl>
|
||||||
|
Jérôme Doucet <jerdct@gmail.com>
|
||||||
Jerrin Shaji George <jerrinsg@gmail.com>
|
Jerrin Shaji George <jerrinsg@gmail.com>
|
||||||
Jess Frazelle <me@jessfraz.com>
|
Jess Frazelle <me@jessfraz.com>
|
||||||
Jesse Szwedko <jesse.szwedko@gmail.com>
|
Jesse Szwedko <jesse.szwedko@gmail.com>
|
||||||
Jesús Espino <jespinog@gmail.com>
|
Jesús Espino <jespinog@gmail.com>
|
||||||
Jia Zhan <jzhan@uber.com>
|
Jia Zhan <jzhan@uber.com>
|
||||||
Jiacai Liu <jiacai2050@gmail.com>
|
Jiacai Liu <jiacai2050@gmail.com>
|
||||||
|
Jiahao Lu <lujjjh@gmail.com>
|
||||||
Jianing Yu <jnyu@google.com>
|
Jianing Yu <jnyu@google.com>
|
||||||
Jianqiao Li <jianqiaoli@google.com>
|
Jianqiao Li <jianqiaoli@google.com>
|
||||||
|
Jiayu Yi <yijiayu@gmail.com>
|
||||||
Jie Ma <jienius@outlook.com>
|
Jie Ma <jienius@outlook.com>
|
||||||
Jihyun Yu <yjh0502@gmail.com>
|
Jihyun Yu <yjh0502@gmail.com>
|
||||||
Jim Cote <jfcote87@gmail.com>
|
Jim Cote <jfcote87@gmail.com>
|
||||||
|
@ -1183,6 +1258,7 @@ Joey Geiger <jgeiger@users.noreply.github.com>
|
||||||
Johan Brandhorst <johan.brandhorst@gmail.com>
|
Johan Brandhorst <johan.brandhorst@gmail.com>
|
||||||
Johan Euphrosine <proppy@google.com>
|
Johan Euphrosine <proppy@google.com>
|
||||||
Johan Jansson <johan.jansson@iki.fi>
|
Johan Jansson <johan.jansson@iki.fi>
|
||||||
|
Johan Knutzen <johan@senri.se>
|
||||||
Johan Sageryd <j@1616.se>
|
Johan Sageryd <j@1616.se>
|
||||||
John Asmuth <jasmuth@gmail.com>
|
John Asmuth <jasmuth@gmail.com>
|
||||||
John Beisley <huin@google.com>
|
John Beisley <huin@google.com>
|
||||||
|
@ -1210,6 +1286,7 @@ Johnny Luo <johnnyluo1980@gmail.com>
|
||||||
Jon Chen <jchen@justin.tv>
|
Jon Chen <jchen@justin.tv>
|
||||||
Jon Johnson <jonjohnson@google.com>
|
Jon Johnson <jonjohnson@google.com>
|
||||||
Jonas Bernoulli <jonas@bernoul.li>
|
Jonas Bernoulli <jonas@bernoul.li>
|
||||||
|
Jonathan Albrecht <jonathan.albrecht@ibm.com>
|
||||||
Jonathan Allie <jonallie@google.com>
|
Jonathan Allie <jonallie@google.com>
|
||||||
Jonathan Amsterdam <jba@google.com>
|
Jonathan Amsterdam <jba@google.com>
|
||||||
Jonathan Boulle <jonathanboulle@gmail.com>
|
Jonathan Boulle <jonathanboulle@gmail.com>
|
||||||
|
@ -1223,6 +1300,7 @@ Jonathan Pentecost <pentecostjonathan@gmail.com>
|
||||||
Jonathan Pittman <jmpittman@google.com> <jonathan.mark.pittman@gmail.com>
|
Jonathan Pittman <jmpittman@google.com> <jonathan.mark.pittman@gmail.com>
|
||||||
Jonathan Rudenberg <jonathan@titanous.com>
|
Jonathan Rudenberg <jonathan@titanous.com>
|
||||||
Jonathan Stacks <jonstacks13@gmail.com>
|
Jonathan Stacks <jonstacks13@gmail.com>
|
||||||
|
Jonathan Swinney <jswinney@amazon.com>
|
||||||
Jonathan Wills <runningwild@gmail.com>
|
Jonathan Wills <runningwild@gmail.com>
|
||||||
Jonathon Lacher <jonathon.lacher@gmail.com>
|
Jonathon Lacher <jonathon.lacher@gmail.com>
|
||||||
Jongmin Kim <atomaths@gmail.com>
|
Jongmin Kim <atomaths@gmail.com>
|
||||||
|
@ -1233,6 +1311,7 @@ Jordan Krage <jmank88@gmail.com>
|
||||||
Jordan Lewis <jordanthelewis@gmail.com>
|
Jordan Lewis <jordanthelewis@gmail.com>
|
||||||
Jordan Liggitt <liggitt@google.com>
|
Jordan Liggitt <liggitt@google.com>
|
||||||
Jordan Rhee <jordanrh@microsoft.com>
|
Jordan Rhee <jordanrh@microsoft.com>
|
||||||
|
Jordan Rupprecht <rupprecht@google.com>
|
||||||
Jordi Martin <jordimartin@gmail.com>
|
Jordi Martin <jordimartin@gmail.com>
|
||||||
Jorge Araya <jorgejavieran@yahoo.com.mx>
|
Jorge Araya <jorgejavieran@yahoo.com.mx>
|
||||||
Jorge L. Fatta <jorge.fatta@auth0.com>
|
Jorge L. Fatta <jorge.fatta@auth0.com>
|
||||||
|
@ -1276,6 +1355,7 @@ Julien Salleyron <julien.salleyron@gmail.com>
|
||||||
Julien Schmidt <google@julienschmidt.com>
|
Julien Schmidt <google@julienschmidt.com>
|
||||||
Julio Montes <julio.montes@intel.com>
|
Julio Montes <julio.montes@intel.com>
|
||||||
Jun Zhang <jim.zoumo@gmail.com>
|
Jun Zhang <jim.zoumo@gmail.com>
|
||||||
|
Junchen Li <junchen.li@arm.com>
|
||||||
Junda Liu <junda@celer.network>
|
Junda Liu <junda@celer.network>
|
||||||
Jungho Ahn <jhahn@google.com>
|
Jungho Ahn <jhahn@google.com>
|
||||||
Junya Hayashi <ledmonster@gmail.com>
|
Junya Hayashi <ledmonster@gmail.com>
|
||||||
|
@ -1287,6 +1367,7 @@ Justin Nuß <nuss.justin@gmail.com>
|
||||||
Justyn Temme <justyntemme@gmail.com>
|
Justyn Temme <justyntemme@gmail.com>
|
||||||
Kai Backman <kaib@golang.org>
|
Kai Backman <kaib@golang.org>
|
||||||
Kai Dong <dokia2357@gmail.com>
|
Kai Dong <dokia2357@gmail.com>
|
||||||
|
Kai Lüke <kai@kinvolk.io>
|
||||||
Kai Trukenmüller <ktye78@gmail.com>
|
Kai Trukenmüller <ktye78@gmail.com>
|
||||||
Kale Blankenship <kale@lemnisys.com>
|
Kale Blankenship <kale@lemnisys.com>
|
||||||
Kaleb Elwert <kelwert@atlassian.com>
|
Kaleb Elwert <kelwert@atlassian.com>
|
||||||
|
@ -1314,6 +1395,7 @@ Kazuhiro Sera <seratch@gmail.com>
|
||||||
KB Sriram <kbsriram@google.com>
|
KB Sriram <kbsriram@google.com>
|
||||||
Keegan Carruthers-Smith <keegan.csmith@gmail.com>
|
Keegan Carruthers-Smith <keegan.csmith@gmail.com>
|
||||||
Kei Son <hey.calmdown@gmail.com>
|
Kei Son <hey.calmdown@gmail.com>
|
||||||
|
Keiichi Hirobe <chalenge.akane@gmail.com>
|
||||||
Keiji Yoshida <keijiyoshida.mail@gmail.com>
|
Keiji Yoshida <keijiyoshida.mail@gmail.com>
|
||||||
Keisuke Kishimoto <keisuke.kishimoto@gmail.com>
|
Keisuke Kishimoto <keisuke.kishimoto@gmail.com>
|
||||||
Keith Ball <inflatablewoman@gmail.com>
|
Keith Ball <inflatablewoman@gmail.com>
|
||||||
|
@ -1322,6 +1404,7 @@ Keith Rarick <kr@xph.us>
|
||||||
Kelly Heller <pestophagous@gmail.com>
|
Kelly Heller <pestophagous@gmail.com>
|
||||||
Kelsey Hightower <kelsey.hightower@gmail.com>
|
Kelsey Hightower <kelsey.hightower@gmail.com>
|
||||||
Kelvin Foo Chuan Lyi <vmirage@gmail.com>
|
Kelvin Foo Chuan Lyi <vmirage@gmail.com>
|
||||||
|
Kemal Elmizan <kemalelmizan@gmail.com>
|
||||||
Ken Friedenbach <kenliz@cruzio.com>
|
Ken Friedenbach <kenliz@cruzio.com>
|
||||||
Ken Rockot <ken@oz.gs> <ken.rockot@gmail.com>
|
Ken Rockot <ken@oz.gs> <ken.rockot@gmail.com>
|
||||||
Ken Sedgwick <ken@bonsai.com>
|
Ken Sedgwick <ken@bonsai.com>
|
||||||
|
@ -1331,6 +1414,7 @@ Kenji Kaneda <kenji.kaneda@gmail.com>
|
||||||
Kenji Yano <kenji.yano@gmail.com>
|
Kenji Yano <kenji.yano@gmail.com>
|
||||||
Kenneth Shaw <kenshaw@gmail.com>
|
Kenneth Shaw <kenshaw@gmail.com>
|
||||||
Kenny Grant <kennygrant@gmail.com>
|
Kenny Grant <kennygrant@gmail.com>
|
||||||
|
Kensei Nakada <handbomusic@gmail.com>
|
||||||
Kenta Mori <zoncoen@gmail.com>
|
Kenta Mori <zoncoen@gmail.com>
|
||||||
Kerollos Magdy <kerolloz@yahoo.com>
|
Kerollos Magdy <kerolloz@yahoo.com>
|
||||||
Ketan Parmar <ketanbparmar@gmail.com>
|
Ketan Parmar <ketanbparmar@gmail.com>
|
||||||
|
@ -1342,10 +1426,12 @@ Kevin Gillette <extemporalgenome@gmail.com>
|
||||||
Kevin Kirsche <kev.kirsche@gmail.com>
|
Kevin Kirsche <kev.kirsche@gmail.com>
|
||||||
Kevin Klues <klueska@gmail.com> <klueska@google.com>
|
Kevin Klues <klueska@gmail.com> <klueska@google.com>
|
||||||
Kevin Malachowski <chowski@google.com>
|
Kevin Malachowski <chowski@google.com>
|
||||||
|
Kevin Parsons <kevpar@microsoft.com>
|
||||||
Kevin Ruffin <kruffin@gmail.com>
|
Kevin Ruffin <kruffin@gmail.com>
|
||||||
Kevin Vu <kevin.m.vu@gmail.com>
|
Kevin Vu <kevin.m.vu@gmail.com>
|
||||||
Kevin Zita <bleedgreenandgold@gmail.com>
|
Kevin Zita <bleedgreenandgold@gmail.com>
|
||||||
Keyan Pishdadian <kpishdadian@gmail.com>
|
Keyan Pishdadian <kpishdadian@gmail.com>
|
||||||
|
Keyuan Li <keyuanli123@gmail.com>
|
||||||
Kezhu Wang <kezhuw@gmail.com>
|
Kezhu Wang <kezhuw@gmail.com>
|
||||||
Khosrow Moossavi <khos2ow@gmail.com>
|
Khosrow Moossavi <khos2ow@gmail.com>
|
||||||
Kieran Colford <kieran@kcolford.com>
|
Kieran Colford <kieran@kcolford.com>
|
||||||
|
@ -1358,6 +1444,7 @@ Kirill Smelkov <kirr@nexedi.com>
|
||||||
Kirill Tatchihin <kirabsuir@gmail.com>
|
Kirill Tatchihin <kirabsuir@gmail.com>
|
||||||
Kirk Han <kirk91.han@gmail.com>
|
Kirk Han <kirk91.han@gmail.com>
|
||||||
Kirklin McDonald <kirklin.mcdonald@gmail.com>
|
Kirklin McDonald <kirklin.mcdonald@gmail.com>
|
||||||
|
KJ Tsanaktsidis <ktsanaktsidis@zendesk.com>
|
||||||
Klaus Post <klauspost@gmail.com>
|
Klaus Post <klauspost@gmail.com>
|
||||||
Kodie Goodwin <kodiegoodwin@gmail.com>
|
Kodie Goodwin <kodiegoodwin@gmail.com>
|
||||||
Koichi Shiraishi <zchee.io@gmail.com>
|
Koichi Shiraishi <zchee.io@gmail.com>
|
||||||
|
@ -1371,6 +1458,7 @@ Kris Kwiatkowski <kris@cloudflare.com>
|
||||||
Kris Nova <kris@nivenly.com>
|
Kris Nova <kris@nivenly.com>
|
||||||
Kris Rousey <krousey@google.com>
|
Kris Rousey <krousey@google.com>
|
||||||
Kristopher Watts <traetox@gmail.com>
|
Kristopher Watts <traetox@gmail.com>
|
||||||
|
Krzysztof Dąbrowski <krzysdabro@live.com>
|
||||||
Kshitij Saraogi <kshitijsaraogi@gmail.com>
|
Kshitij Saraogi <kshitijsaraogi@gmail.com>
|
||||||
Kun Li <likunarmstrong@gmail.com>
|
Kun Li <likunarmstrong@gmail.com>
|
||||||
Kunpei Sakai <namusyaka@gmail.com>
|
Kunpei Sakai <namusyaka@gmail.com>
|
||||||
|
@ -1412,8 +1500,10 @@ Leonardo Comelli <leonardo.comelli@gmail.com>
|
||||||
Leonel Quinteros <leonel.quinteros@gmail.com>
|
Leonel Quinteros <leonel.quinteros@gmail.com>
|
||||||
Lev Shamardin <shamardin@gmail.com>
|
Lev Shamardin <shamardin@gmail.com>
|
||||||
Lewin Bormann <lewin.bormann@gmail.com>
|
Lewin Bormann <lewin.bormann@gmail.com>
|
||||||
|
Lewis Waddicor <nemesismk2@gmail.com>
|
||||||
Liam Haworth <liam@haworth.id.au>
|
Liam Haworth <liam@haworth.id.au>
|
||||||
Lily Chung <lilithkchung@gmail.com>
|
Lily Chung <lilithkchung@gmail.com>
|
||||||
|
Lingchao Xin <douglarek@gmail.com>
|
||||||
Lion Yang <lion@aosc.xyz>
|
Lion Yang <lion@aosc.xyz>
|
||||||
Liz Rice <liz@lizrice.com>
|
Liz Rice <liz@lizrice.com>
|
||||||
Lloyd Dewolf <foolswisdom@gmail.com>
|
Lloyd Dewolf <foolswisdom@gmail.com>
|
||||||
|
@ -1427,6 +1517,7 @@ Luan Santos <cfcluan@gmail.com>
|
||||||
Lubomir I. Ivanov <neolit123@gmail.com>
|
Lubomir I. Ivanov <neolit123@gmail.com>
|
||||||
Luca Bruno <luca.bruno@coreos.com>
|
Luca Bruno <luca.bruno@coreos.com>
|
||||||
Luca Greco <luca.greco@alcacoop.it>
|
Luca Greco <luca.greco@alcacoop.it>
|
||||||
|
Luca Spiller <luca@stackednotion.com>
|
||||||
Lucas Bremgartner <lucas.bremgartner@gmail.com>
|
Lucas Bremgartner <lucas.bremgartner@gmail.com>
|
||||||
Lucas Clemente <lclemente@google.com>
|
Lucas Clemente <lclemente@google.com>
|
||||||
Lucien Stuker <lucien.stuker@gmail.com>
|
Lucien Stuker <lucien.stuker@gmail.com>
|
||||||
|
@ -1450,6 +1541,8 @@ Maarten Bezemer <maarten.bezemer@gmail.com>
|
||||||
Maciej Dębski <maciejd@google.com>
|
Maciej Dębski <maciejd@google.com>
|
||||||
Madhu Rajanna <madhupr007@gmail.com>
|
Madhu Rajanna <madhupr007@gmail.com>
|
||||||
Magnus Hiie <magnus.hiie@gmail.com>
|
Magnus Hiie <magnus.hiie@gmail.com>
|
||||||
|
Mahdi Hosseini Moghaddam <seyed.mahdi.hosseini.moghaddam@ibm.com>
|
||||||
|
Maia Lee <maia.lee@leftfieldlabs.com>
|
||||||
Maicon Costa <maiconscosta@gmail.com>
|
Maicon Costa <maiconscosta@gmail.com>
|
||||||
Mak Kolybabi <mak@kolybabi.com>
|
Mak Kolybabi <mak@kolybabi.com>
|
||||||
Maksym Trykur <maksym.trykur@gmail.com>
|
Maksym Trykur <maksym.trykur@gmail.com>
|
||||||
|
@ -1470,6 +1563,7 @@ Marcel Edmund Franke <marcel.edmund.franke@gmail.com>
|
||||||
Marcel van Lohuizen <mpvl@golang.org>
|
Marcel van Lohuizen <mpvl@golang.org>
|
||||||
Marcelo Cantos <marcelo.cantos@gmail.com>
|
Marcelo Cantos <marcelo.cantos@gmail.com>
|
||||||
Marcelo E. Magallon <marcelo.magallon@gmail.com>
|
Marcelo E. Magallon <marcelo.magallon@gmail.com>
|
||||||
|
Marco Gazerro <gazerro@open2b.com>
|
||||||
Marco Hennings <marco.hennings@freiheit.com>
|
Marco Hennings <marco.hennings@freiheit.com>
|
||||||
Marcus Weiner <marcus.weiner@gmail.com>
|
Marcus Weiner <marcus.weiner@gmail.com>
|
||||||
Marcus Willock <crazcalm@gmail.com>
|
Marcus Willock <crazcalm@gmail.com>
|
||||||
|
@ -1481,6 +1575,7 @@ Marius A. Eriksen <marius@grailbio.com>
|
||||||
Marius Nuennerich <mnu@google.com>
|
Marius Nuennerich <mnu@google.com>
|
||||||
Mark Adams <mark@markadams.me>
|
Mark Adams <mark@markadams.me>
|
||||||
Mark Bucciarelli <mkbucc@gmail.com>
|
Mark Bucciarelli <mkbucc@gmail.com>
|
||||||
|
Mark Dain <mark@markdain.net>
|
||||||
Mark Glines <mark@glines.org>
|
Mark Glines <mark@glines.org>
|
||||||
Mark Harrison <marhar@google.com>
|
Mark Harrison <marhar@google.com>
|
||||||
Mark Percival <m@mdp.im>
|
Mark Percival <m@mdp.im>
|
||||||
|
@ -1533,6 +1628,7 @@ Máté Gulyás <mgulyas86@gmail.com>
|
||||||
Matej Baćo <matejbaco@gmail.com>
|
Matej Baćo <matejbaco@gmail.com>
|
||||||
Mateus Amin <mateus.amin@gmail.com>
|
Mateus Amin <mateus.amin@gmail.com>
|
||||||
Mateusz Czapliński <czapkofan@gmail.com>
|
Mateusz Czapliński <czapkofan@gmail.com>
|
||||||
|
Matheus Alcantara <matheusssilv97@gmail.com>
|
||||||
Mathias Beke <git@denbeke.be>
|
Mathias Beke <git@denbeke.be>
|
||||||
Mathias Hall-Andersen <mathias@hall-andersen.dk>
|
Mathias Hall-Andersen <mathias@hall-andersen.dk>
|
||||||
Mathias Leppich <mleppich@muhqu.de>
|
Mathias Leppich <mleppich@muhqu.de>
|
||||||
|
@ -1566,6 +1662,7 @@ Matthew Waters <mwwaters@gmail.com>
|
||||||
Matthieu Hauglustaine <matt.hauglustaine@gmail.com>
|
Matthieu Hauglustaine <matt.hauglustaine@gmail.com>
|
||||||
Matthieu Olivier <olivier.matthieu@gmail.com>
|
Matthieu Olivier <olivier.matthieu@gmail.com>
|
||||||
Matthijs Kooijman <matthijs@stdin.nl>
|
Matthijs Kooijman <matthijs@stdin.nl>
|
||||||
|
Max Drosdo.www <g1ran1q@gmail.com>
|
||||||
Max Riveiro <kavu13@gmail.com>
|
Max Riveiro <kavu13@gmail.com>
|
||||||
Max Schmitt <max@schmitt.mx>
|
Max Schmitt <max@schmitt.mx>
|
||||||
Max Semenik <maxsem.wiki@gmail.com>
|
Max Semenik <maxsem.wiki@gmail.com>
|
||||||
|
@ -1603,6 +1700,7 @@ Michael Hudson-Doyle <michael.hudson@linaro.org>
|
||||||
Michael Kasch <michael.kasch@gmail.com>
|
Michael Kasch <michael.kasch@gmail.com>
|
||||||
Michael Käufl <golang@c.michael-kaeufl.de>
|
Michael Käufl <golang@c.michael-kaeufl.de>
|
||||||
Michael Kelly <mjk@google.com>
|
Michael Kelly <mjk@google.com>
|
||||||
|
Michaël Lévesque-Dion <mlevesquedion@google.com>
|
||||||
Michael Lewis <mikelikespie@gmail.com>
|
Michael Lewis <mikelikespie@gmail.com>
|
||||||
Michael MacInnis <Michael.P.MacInnis@gmail.com>
|
Michael MacInnis <Michael.P.MacInnis@gmail.com>
|
||||||
Michael Marineau <michael.marineau@coreos.com>
|
Michael Marineau <michael.marineau@coreos.com>
|
||||||
|
@ -1624,6 +1722,7 @@ Michael Teichgräber <mteichgraeber@gmx.de> <mt4swm@googlemail.com>
|
||||||
Michael Traver <mtraver@google.com>
|
Michael Traver <mtraver@google.com>
|
||||||
Michael Vetter <g.bluehut@gmail.com>
|
Michael Vetter <g.bluehut@gmail.com>
|
||||||
Michael Vogt <mvo@ubuntu.com>
|
Michael Vogt <mvo@ubuntu.com>
|
||||||
|
Michail Kargakis <mkargaki@redhat.com>
|
||||||
Michal Bohuslávek <mbohuslavek@gmail.com>
|
Michal Bohuslávek <mbohuslavek@gmail.com>
|
||||||
Michal Cierniak <cierniak@google.com>
|
Michal Cierniak <cierniak@google.com>
|
||||||
Michał Derkacz <ziutek@lnet.pl>
|
Michał Derkacz <ziutek@lnet.pl>
|
||||||
|
@ -1633,6 +1732,7 @@ Michal Pristas <michal.pristas@gmail.com>
|
||||||
Michal Rostecki <mrostecki@suse.de>
|
Michal Rostecki <mrostecki@suse.de>
|
||||||
Michalis Kargakis <michaliskargakis@gmail.com>
|
Michalis Kargakis <michaliskargakis@gmail.com>
|
||||||
Michel Lespinasse <walken@google.com>
|
Michel Lespinasse <walken@google.com>
|
||||||
|
Michele Di Pede <michele.di.pede@gmail.com>
|
||||||
Mickael Kerjean <mickael.kerjean@gmail.com>
|
Mickael Kerjean <mickael.kerjean@gmail.com>
|
||||||
Mickey Reiss <mickeyreiss@gmail.com>
|
Mickey Reiss <mickeyreiss@gmail.com>
|
||||||
Miek Gieben <miek@miek.nl> <remigius.gieben@gmail.com>
|
Miek Gieben <miek@miek.nl> <remigius.gieben@gmail.com>
|
||||||
|
@ -1670,6 +1770,7 @@ Miquel Sabaté Solà <mikisabate@gmail.com>
|
||||||
Mirko Hansen <baaazen@gmail.com>
|
Mirko Hansen <baaazen@gmail.com>
|
||||||
Miroslav Genov <mgenov@gmail.com>
|
Miroslav Genov <mgenov@gmail.com>
|
||||||
Misty De Meo <mistydemeo@gmail.com>
|
Misty De Meo <mistydemeo@gmail.com>
|
||||||
|
Mohamed Attahri <mohamed@attahri.com>
|
||||||
Mohit Agarwal <mohit@sdf.org>
|
Mohit Agarwal <mohit@sdf.org>
|
||||||
Mohit kumar Bajoria <mohitbajo36@gmail.com>
|
Mohit kumar Bajoria <mohitbajo36@gmail.com>
|
||||||
Mohit Verma <vmohit.93@gmail.com>
|
Mohit Verma <vmohit.93@gmail.com>
|
||||||
|
@ -1683,6 +1784,7 @@ Môshe van der Sterre <moshevds@gmail.com>
|
||||||
Mostyn Bramley-Moore <mostyn@antipode.se>
|
Mostyn Bramley-Moore <mostyn@antipode.se>
|
||||||
Mrunal Patel <mrunalp@gmail.com>
|
Mrunal Patel <mrunalp@gmail.com>
|
||||||
Muhammad Falak R Wani <falakreyaz@gmail.com>
|
Muhammad Falak R Wani <falakreyaz@gmail.com>
|
||||||
|
Muhammad Hamza Farrukh <hamzafarrukh141@gmail.com>
|
||||||
Muhammed Uluyol <uluyol0@gmail.com>
|
Muhammed Uluyol <uluyol0@gmail.com>
|
||||||
Muir Manders <muir@mnd.rs>
|
Muir Manders <muir@mnd.rs>
|
||||||
Mukesh Sharma <sharma.mukesh439@gmail.com>
|
Mukesh Sharma <sharma.mukesh439@gmail.com>
|
||||||
|
@ -1692,6 +1794,7 @@ Naman Aggarwal <aggarwal.nam@gmail.com>
|
||||||
Nan Deng <monnand@gmail.com>
|
Nan Deng <monnand@gmail.com>
|
||||||
Nao Yonashiro <owan.orisano@gmail.com>
|
Nao Yonashiro <owan.orisano@gmail.com>
|
||||||
Naoki Kanatani <k12naoki@gmail.com>
|
Naoki Kanatani <k12naoki@gmail.com>
|
||||||
|
Natanael Copa <ncopa@mirantis.com>
|
||||||
Nate Wilkinson <nathanwilk7@gmail.com>
|
Nate Wilkinson <nathanwilk7@gmail.com>
|
||||||
Nathan Cantelmo <n.cantelmo@gmail.com>
|
Nathan Cantelmo <n.cantelmo@gmail.com>
|
||||||
Nathan Caza <mastercactapus@gmail.com>
|
Nathan Caza <mastercactapus@gmail.com>
|
||||||
|
@ -1708,6 +1811,7 @@ Nathaniel Cook <nvcook42@gmail.com>
|
||||||
Naveen Kumar Sangi <naveenkumarsangi@protonmail.com>
|
Naveen Kumar Sangi <naveenkumarsangi@protonmail.com>
|
||||||
Neeilan Selvalingam <neeilan96@gmail.com>
|
Neeilan Selvalingam <neeilan96@gmail.com>
|
||||||
Neelesh Chandola <neelesh.c98@gmail.com>
|
Neelesh Chandola <neelesh.c98@gmail.com>
|
||||||
|
Nehal J Wani <nehaljw.kkd1@gmail.com>
|
||||||
Neil Lyons <nwjlyons@googlemail.com>
|
Neil Lyons <nwjlyons@googlemail.com>
|
||||||
Neuman Vong <neuman.vong@gmail.com>
|
Neuman Vong <neuman.vong@gmail.com>
|
||||||
Neven Sajko <nsajko@gmail.com>
|
Neven Sajko <nsajko@gmail.com>
|
||||||
|
@ -1760,6 +1864,7 @@ Noel Georgi <git@frezbo.com>
|
||||||
Norberto Lopes <nlopes.ml@gmail.com>
|
Norberto Lopes <nlopes.ml@gmail.com>
|
||||||
Norman B. Lancaster <qbradq@gmail.com>
|
Norman B. Lancaster <qbradq@gmail.com>
|
||||||
Nuno Cruces <ncruces@users.noreply.github.com>
|
Nuno Cruces <ncruces@users.noreply.github.com>
|
||||||
|
Obei Sideg <obei.sideg@gmail.com>
|
||||||
Obeyda Djeffal <djefobey@gmail.com>
|
Obeyda Djeffal <djefobey@gmail.com>
|
||||||
Odin Ugedal <odin@ugedal.com>
|
Odin Ugedal <odin@ugedal.com>
|
||||||
Oleg Bulatov <dmage@yandex-team.ru>
|
Oleg Bulatov <dmage@yandex-team.ru>
|
||||||
|
@ -1769,12 +1874,17 @@ Oling Cat <olingcat@gmail.com>
|
||||||
Oliver Hookins <ohookins@gmail.com>
|
Oliver Hookins <ohookins@gmail.com>
|
||||||
Oliver Powell <oliverpowell84@gmail.com>
|
Oliver Powell <oliverpowell84@gmail.com>
|
||||||
Oliver Stenbom <ostenbom@pivotal.io>
|
Oliver Stenbom <ostenbom@pivotal.io>
|
||||||
|
Oliver Tan <otan@cockroachlabs.com>
|
||||||
Oliver Tonnhofer <olt@bogosoft.com>
|
Oliver Tonnhofer <olt@bogosoft.com>
|
||||||
Olivier Antoine <olivier.antoine@gmail.com>
|
Olivier Antoine <olivier.antoine@gmail.com>
|
||||||
Olivier Duperray <duperray.olivier@gmail.com>
|
Olivier Duperray <duperray.olivier@gmail.com>
|
||||||
Olivier Poitrey <rs@dailymotion.com>
|
Olivier Poitrey <rs@dailymotion.com>
|
||||||
Olivier Saingre <osaingre@gmail.com>
|
Olivier Saingre <osaingre@gmail.com>
|
||||||
|
Olivier Wulveryck <olivier.wulveryck@gmail.com>
|
||||||
Omar Jarjur <ojarjur@google.com>
|
Omar Jarjur <ojarjur@google.com>
|
||||||
|
Onkar Jadhav <omjadhav2610@gmail.com>
|
||||||
|
Ori Bernstein <ori@eigenstate.org>
|
||||||
|
Ori Rawlings <orirawlings@gmail.com>
|
||||||
Oryan Moshe <iamoryanmoshe@gmail.com>
|
Oryan Moshe <iamoryanmoshe@gmail.com>
|
||||||
Osamu TONOMORI <osamingo@gmail.com>
|
Osamu TONOMORI <osamingo@gmail.com>
|
||||||
Özgür Kesim <oec-go@kesim.org>
|
Özgür Kesim <oec-go@kesim.org>
|
||||||
|
@ -1798,7 +1908,9 @@ Pat Moroney <pat@pat.email>
|
||||||
Patrick Barker <barkerp@vmware.com>
|
Patrick Barker <barkerp@vmware.com>
|
||||||
Patrick Crosby <patrick@stathat.com>
|
Patrick Crosby <patrick@stathat.com>
|
||||||
Patrick Gavlin <pgavlin@gmail.com>
|
Patrick Gavlin <pgavlin@gmail.com>
|
||||||
|
Patrick Gundlach <gundlach@speedata.de>
|
||||||
Patrick Higgins <patrick.allen.higgins@gmail.com>
|
Patrick Higgins <patrick.allen.higgins@gmail.com>
|
||||||
|
Patrick Jones <ithuriel@google.com>
|
||||||
Patrick Lee <pattyshack101@gmail.com>
|
Patrick Lee <pattyshack101@gmail.com>
|
||||||
Patrick Mézard <patrick@mezard.eu>
|
Patrick Mézard <patrick@mezard.eu>
|
||||||
Patrick Mylund Nielsen <patrick@patrickmn.com>
|
Patrick Mylund Nielsen <patrick@patrickmn.com>
|
||||||
|
@ -1811,6 +1923,9 @@ Paul Borman <borman@google.com>
|
||||||
Paul Boyd <boyd.paul2@gmail.com>
|
Paul Boyd <boyd.paul2@gmail.com>
|
||||||
Paul Chang <paulchang@google.com>
|
Paul Chang <paulchang@google.com>
|
||||||
Paul D. Weber <x0bdev@gmail.com>
|
Paul D. Weber <x0bdev@gmail.com>
|
||||||
|
Paul Davis <43160081+Pawls@users.noreply.github.com>
|
||||||
|
Paul E. Murphy <murp@ibm.com>
|
||||||
|
Paul Forgey <paulf@tessier-ashpool.net>
|
||||||
Paul Hammond <paul@paulhammond.org>
|
Paul Hammond <paul@paulhammond.org>
|
||||||
Paul Hankin <paulhankin@google.com>
|
Paul Hankin <paulhankin@google.com>
|
||||||
Paul Jolly <paul@myitcv.org.uk>
|
Paul Jolly <paul@myitcv.org.uk>
|
||||||
|
@ -1836,7 +1951,9 @@ Pavel Zinovkin <pavel.zinovkin@gmail.com>
|
||||||
Pavlo Sumkin <ymkins@gmail.com>
|
Pavlo Sumkin <ymkins@gmail.com>
|
||||||
Pawel Knap <pawelknap88@gmail.com>
|
Pawel Knap <pawelknap88@gmail.com>
|
||||||
Pawel Szczur <filemon@google.com>
|
Pawel Szczur <filemon@google.com>
|
||||||
|
Paweł Szulik <pawel.szulik@intel.com>
|
||||||
Pei Xian Chee <luciolas1991@gmail.com>
|
Pei Xian Chee <luciolas1991@gmail.com>
|
||||||
|
Pei-Ming Wu <p408865@gmail.com>
|
||||||
Percy Wegmann <ox.to.a.cart@gmail.com>
|
Percy Wegmann <ox.to.a.cart@gmail.com>
|
||||||
Perry Abbott <perry.j.abbott@gmail.com>
|
Perry Abbott <perry.j.abbott@gmail.com>
|
||||||
Petar Dambovaliev <petar.atanasov.1987@gmail.com>
|
Petar Dambovaliev <petar.atanasov.1987@gmail.com>
|
||||||
|
@ -1876,6 +1993,7 @@ Philip Hofer <phofer@umich.edu>
|
||||||
Philip K. Warren <pkwarren@gmail.com>
|
Philip K. Warren <pkwarren@gmail.com>
|
||||||
Philip Nelson <me@pnelson.ca>
|
Philip Nelson <me@pnelson.ca>
|
||||||
Philipp Stephani <phst@google.com>
|
Philipp Stephani <phst@google.com>
|
||||||
|
Phillip Campbell <15082+phillc@users.noreply.github.com>
|
||||||
Pierre Carru <pierre.carru@eshard.com>
|
Pierre Carru <pierre.carru@eshard.com>
|
||||||
Pierre Durand <pierredurand@gmail.com>
|
Pierre Durand <pierredurand@gmail.com>
|
||||||
Pierre Prinetti <pierreprinetti@gmail.com>
|
Pierre Prinetti <pierreprinetti@gmail.com>
|
||||||
|
@ -1885,6 +2003,7 @@ Pieter Droogendijk <pieter@binky.org.uk>
|
||||||
Pietro Gagliardi <pietro10@mac.com>
|
Pietro Gagliardi <pietro10@mac.com>
|
||||||
Piyush Mishra <piyush@codeitout.com>
|
Piyush Mishra <piyush@codeitout.com>
|
||||||
Plekhanov Maxim <kishtatix@gmail.com>
|
Plekhanov Maxim <kishtatix@gmail.com>
|
||||||
|
Poh Zi How <poh.zihow@gmail.com>
|
||||||
Polina Osadcha <polliosa@google.com>
|
Polina Osadcha <polliosa@google.com>
|
||||||
Pontus Leitzler <leitzler@gmail.com>
|
Pontus Leitzler <leitzler@gmail.com>
|
||||||
Povilas Versockas <p.versockas@gmail.com>
|
Povilas Versockas <p.versockas@gmail.com>
|
||||||
|
@ -1904,14 +2023,17 @@ Quentin Perez <qperez@ocs.online.net>
|
||||||
Quentin Renard <contact@asticode.com>
|
Quentin Renard <contact@asticode.com>
|
||||||
Quentin Smith <quentin@golang.org>
|
Quentin Smith <quentin@golang.org>
|
||||||
Quey-Liang Kao <s101062801@m101.nthu.edu.tw>
|
Quey-Liang Kao <s101062801@m101.nthu.edu.tw>
|
||||||
|
Quim Muntal <quimmuntal@gmail.com>
|
||||||
Quinn Slack <sqs@sourcegraph.com>
|
Quinn Slack <sqs@sourcegraph.com>
|
||||||
Quinten Yearsley <qyearsley@chromium.org>
|
Quinten Yearsley <qyearsley@chromium.org>
|
||||||
Quoc-Viet Nguyen <afelion@gmail.com>
|
Quoc-Viet Nguyen <afelion@gmail.com>
|
||||||
|
Radek Simko <radek.simko@gmail.com>
|
||||||
Radek Sohlich <sohlich@gmail.com>
|
Radek Sohlich <sohlich@gmail.com>
|
||||||
Radu Berinde <radu@cockroachlabs.com>
|
Radu Berinde <radu@cockroachlabs.com>
|
||||||
Rafal Jeczalik <rjeczalik@gmail.com>
|
Rafal Jeczalik <rjeczalik@gmail.com>
|
||||||
Raghavendra Nagaraj <jamdagni86@gmail.com>
|
Raghavendra Nagaraj <jamdagni86@gmail.com>
|
||||||
Rahul Chaudhry <rahulchaudhry@chromium.org>
|
Rahul Chaudhry <rahulchaudhry@chromium.org>
|
||||||
|
Rahul Wadhwani <rahulwadhwani21@gmail.com>
|
||||||
Raif S. Naffah <go@naffah-raif.name>
|
Raif S. Naffah <go@naffah-raif.name>
|
||||||
Rajat Goel <rajat.goel2010@gmail.com>
|
Rajat Goel <rajat.goel2010@gmail.com>
|
||||||
Rajath Agasthya <rajathagasthya@gmail.com>
|
Rajath Agasthya <rajathagasthya@gmail.com>
|
||||||
|
@ -1935,6 +2057,7 @@ Ren Ogaki <re.yuz77777@gmail.com>
|
||||||
Rens Rikkerink <Ikkerens@users.noreply.github.com>
|
Rens Rikkerink <Ikkerens@users.noreply.github.com>
|
||||||
Rhys Hiltner <rhys@justin.tv>
|
Rhys Hiltner <rhys@justin.tv>
|
||||||
Ricardo Padilha <ricardospadilha@gmail.com>
|
Ricardo Padilha <ricardospadilha@gmail.com>
|
||||||
|
Ricardo Pchevuzinske Katz <ricardo.katz@serpro.gov.br>
|
||||||
Ricardo Seriani <ricardo.seriani@gmail.com>
|
Ricardo Seriani <ricardo.seriani@gmail.com>
|
||||||
Richard Barnes <rlb@ipv.sx>
|
Richard Barnes <rlb@ipv.sx>
|
||||||
Richard Crowley <r@rcrowley.org>
|
Richard Crowley <r@rcrowley.org>
|
||||||
|
@ -1991,6 +2114,7 @@ Roman Kollár <roman.kollar.0@gmail.com>
|
||||||
Roman Shchekin <mrqtros@gmail.com>
|
Roman Shchekin <mrqtros@gmail.com>
|
||||||
Ron Hashimoto <mail@h2so5.net>
|
Ron Hashimoto <mail@h2so5.net>
|
||||||
Ron Minnich <rminnich@gmail.com>
|
Ron Minnich <rminnich@gmail.com>
|
||||||
|
Ronnie Ebrin <ebrin.ronnie@protonmail.com>
|
||||||
Ross Chater <rdchater@gmail.com>
|
Ross Chater <rdchater@gmail.com>
|
||||||
Ross Kinsey <rossikinsey@gmail.com>
|
Ross Kinsey <rossikinsey@gmail.com>
|
||||||
Ross Light <light@google.com> <rlight2@gmail.com>
|
Ross Light <light@google.com> <rlight2@gmail.com>
|
||||||
|
@ -2010,6 +2134,7 @@ Ryan Brown <ribrdb@google.com>
|
||||||
Ryan Canty <jrcanty@gmail.com>
|
Ryan Canty <jrcanty@gmail.com>
|
||||||
Ryan Dahl <ry@tinyclouds.org>
|
Ryan Dahl <ry@tinyclouds.org>
|
||||||
Ryan Hitchman <hitchmanr@gmail.com>
|
Ryan Hitchman <hitchmanr@gmail.com>
|
||||||
|
Ryan Kohler <ryankohler@google.com>
|
||||||
Ryan Lower <rpjlower@gmail.com>
|
Ryan Lower <rpjlower@gmail.com>
|
||||||
Ryan Roden-Corrent <ryan@rcorre.net>
|
Ryan Roden-Corrent <ryan@rcorre.net>
|
||||||
Ryan Seys <ryan@ryanseys.com>
|
Ryan Seys <ryan@ryanseys.com>
|
||||||
|
@ -2023,7 +2148,9 @@ S.Çağlar Onur <caglar@10ur.org>
|
||||||
Sabin Mihai Rapan <sabin.rapan@gmail.com>
|
Sabin Mihai Rapan <sabin.rapan@gmail.com>
|
||||||
Sad Pencil <qh06@qq.com>
|
Sad Pencil <qh06@qq.com>
|
||||||
Sai Cheemalapati <saicheems@google.com>
|
Sai Cheemalapati <saicheems@google.com>
|
||||||
|
Sai Kiran Dasika <kirandasika30@gmail.com>
|
||||||
Sakeven Jiang <jc5930@sina.cn>
|
Sakeven Jiang <jc5930@sina.cn>
|
||||||
|
Salaheddin M. Mahmud <salah.mahmud@gmail.com>
|
||||||
Salmān Aljammāz <s@0x65.net>
|
Salmān Aljammāz <s@0x65.net>
|
||||||
Sam Arnold <sarnold64@bloomberg.net>
|
Sam Arnold <sarnold64@bloomberg.net>
|
||||||
Sam Boyer <tech@samboyer.org>
|
Sam Boyer <tech@samboyer.org>
|
||||||
|
@ -2033,6 +2160,7 @@ Sam Ding <samding@ca.ibm.com>
|
||||||
Sam Hug <samuel.b.hug@gmail.com>
|
Sam Hug <samuel.b.hug@gmail.com>
|
||||||
Sam Thorogood <thorogood@google.com> <sam.thorogood@gmail.com>
|
Sam Thorogood <thorogood@google.com> <sam.thorogood@gmail.com>
|
||||||
Sam Whited <sam@samwhited.com>
|
Sam Whited <sam@samwhited.com>
|
||||||
|
Sam Xie <xsambundy@gmail.com>
|
||||||
Sameer Ajmani <sameer@golang.org> <ajmani@gmail.com>
|
Sameer Ajmani <sameer@golang.org> <ajmani@gmail.com>
|
||||||
Sami Commerot <samic@google.com>
|
Sami Commerot <samic@google.com>
|
||||||
Sami Pönkänen <sami.ponkanen@gmail.com>
|
Sami Pönkänen <sami.ponkanen@gmail.com>
|
||||||
|
@ -2042,6 +2170,7 @@ Samuele Pedroni <pedronis@lucediurna.net>
|
||||||
Sander van Harmelen <sander@vanharmelen.nl>
|
Sander van Harmelen <sander@vanharmelen.nl>
|
||||||
Sanjay Menakuru <balasanjay@gmail.com>
|
Sanjay Menakuru <balasanjay@gmail.com>
|
||||||
Santhosh Kumar Tekuri <santhosh.tekuri@gmail.com>
|
Santhosh Kumar Tekuri <santhosh.tekuri@gmail.com>
|
||||||
|
Santiago De la Cruz <51337247+xhit@users.noreply.github.com>
|
||||||
Sarah Adams <shadams@google.com>
|
Sarah Adams <shadams@google.com>
|
||||||
Sardorbek Pulatov <sardorbek.pulatov@outlook.com>
|
Sardorbek Pulatov <sardorbek.pulatov@outlook.com>
|
||||||
Sascha Brawer <sascha@brawer.ch>
|
Sascha Brawer <sascha@brawer.ch>
|
||||||
|
@ -2062,6 +2191,7 @@ Sean Chittenden <seanc@joyent.com>
|
||||||
Sean Christopherson <sean.j.christopherson@intel.com>
|
Sean Christopherson <sean.j.christopherson@intel.com>
|
||||||
Sean Dolphin <Sean.Dolphin@kpcompass.com>
|
Sean Dolphin <Sean.Dolphin@kpcompass.com>
|
||||||
Sean Harger <sharger@google.com>
|
Sean Harger <sharger@google.com>
|
||||||
|
Sean Hildebrand <seanwhildebrand@gmail.com>
|
||||||
Sean Liao <seankhliao@gmail.com>
|
Sean Liao <seankhliao@gmail.com>
|
||||||
Sean Rees <sean@erifax.org>
|
Sean Rees <sean@erifax.org>
|
||||||
Sebastiaan van Stijn <github@gone.nl>
|
Sebastiaan van Stijn <github@gone.nl>
|
||||||
|
@ -2094,10 +2224,12 @@ Serhii Aheienko <serhii.aheienko@gmail.com>
|
||||||
Seth Hoenig <seth.a.hoenig@gmail.com>
|
Seth Hoenig <seth.a.hoenig@gmail.com>
|
||||||
Seth Vargo <sethvargo@gmail.com>
|
Seth Vargo <sethvargo@gmail.com>
|
||||||
Shahar Kohanim <skohanim@gmail.com>
|
Shahar Kohanim <skohanim@gmail.com>
|
||||||
|
Shailesh Suryawanshi <ss.shailesh28@gmail.com>
|
||||||
Shamil Garatuev <garatuev@gmail.com>
|
Shamil Garatuev <garatuev@gmail.com>
|
||||||
Shane Hansen <shanemhansen@gmail.com>
|
Shane Hansen <shanemhansen@gmail.com>
|
||||||
Shang Jian Ding <sding3@ncsu.edu>
|
Shang Jian Ding <sding3@ncsu.edu>
|
||||||
Shaozhen Ding <dsz0111@gmail.com>
|
Shaozhen Ding <dsz0111@gmail.com>
|
||||||
|
Shaquille Que <shaquille@golang.org>
|
||||||
Shaquille Wyan Que <shaqqywyan@gmail.com>
|
Shaquille Wyan Que <shaqqywyan@gmail.com>
|
||||||
Shaun Dunning <shaun.dunning@uservoice.com>
|
Shaun Dunning <shaun.dunning@uservoice.com>
|
||||||
Shawn Elliott <selliott@microsoft.com>
|
Shawn Elliott <selliott@microsoft.com>
|
||||||
|
@ -2108,8 +2240,11 @@ Shenghou Ma <minux@golang.org> <minux.ma@gmail.com>
|
||||||
Shengjing Zhu <zsj950618@gmail.com>
|
Shengjing Zhu <zsj950618@gmail.com>
|
||||||
Shengyu Zhang <shengyu.zhang@chaitin.com>
|
Shengyu Zhang <shengyu.zhang@chaitin.com>
|
||||||
Shi Han Ng <shihanng@gmail.com>
|
Shi Han Ng <shihanng@gmail.com>
|
||||||
|
ShihCheng Tu <mrtoastcheng@gmail.com>
|
||||||
Shijie Hao <haormj@gmail.com>
|
Shijie Hao <haormj@gmail.com>
|
||||||
|
Shin Fan <shinfan@google.com>
|
||||||
Shinji Tanaka <shinji.tanaka@gmail.com>
|
Shinji Tanaka <shinji.tanaka@gmail.com>
|
||||||
|
Shinnosuke Sawada <6warashi9@gmail.com>
|
||||||
Shintaro Kaneko <kaneshin0120@gmail.com>
|
Shintaro Kaneko <kaneshin0120@gmail.com>
|
||||||
Shivakumar GN <shivakumar.gn@gmail.com>
|
Shivakumar GN <shivakumar.gn@gmail.com>
|
||||||
Shivani Singhal <shivani.singhal2804@gmail.com>
|
Shivani Singhal <shivani.singhal2804@gmail.com>
|
||||||
|
@ -2121,17 +2256,21 @@ Silvan Jegen <s.jegen@gmail.com>
|
||||||
Simarpreet Singh <simar@linux.com>
|
Simarpreet Singh <simar@linux.com>
|
||||||
Simon Drake <simondrake1990@gmail.com>
|
Simon Drake <simondrake1990@gmail.com>
|
||||||
Simon Ferquel <simon.ferquel@docker.com>
|
Simon Ferquel <simon.ferquel@docker.com>
|
||||||
|
Simon Frei <freisim93@gmail.com>
|
||||||
Simon Jefford <simon.jefford@gmail.com>
|
Simon Jefford <simon.jefford@gmail.com>
|
||||||
Simon Rawet <simon@rawet.se>
|
Simon Rawet <simon@rawet.se>
|
||||||
Simon Rozman <simon@rozman.si>
|
Simon Rozman <simon@rozman.si>
|
||||||
|
Simon Ser <contact@emersion.fr>
|
||||||
Simon Thulbourn <simon+github@thulbourn.com>
|
Simon Thulbourn <simon+github@thulbourn.com>
|
||||||
Simon Whitehead <chemnova@gmail.com>
|
Simon Whitehead <chemnova@gmail.com>
|
||||||
Sina Siadat <siadat@gmail.com>
|
Sina Siadat <siadat@gmail.com>
|
||||||
Sjoerd Siebinga <sjoerd.siebinga@gmail.com>
|
Sjoerd Siebinga <sjoerd.siebinga@gmail.com>
|
||||||
Sokolov Yura <funny.falcon@gmail.com>
|
Sokolov Yura <funny.falcon@gmail.com>
|
||||||
Song Gao <song@gao.io>
|
Song Gao <song@gao.io>
|
||||||
|
Songjiayang <songjiayang1@gmail.com>
|
||||||
Soojin Nam <jsunam@gmail.com>
|
Soojin Nam <jsunam@gmail.com>
|
||||||
Søren L. Hansen <soren@linux2go.dk>
|
Søren L. Hansen <soren@linux2go.dk>
|
||||||
|
Sparrow Li <liyuancylx@gmail.com>
|
||||||
Spencer Kocot <spencerkocot@gmail.com>
|
Spencer Kocot <spencerkocot@gmail.com>
|
||||||
Spencer Nelson <s@spenczar.com>
|
Spencer Nelson <s@spenczar.com>
|
||||||
Spencer Tung <spencertung@google.com>
|
Spencer Tung <spencertung@google.com>
|
||||||
|
@ -2140,12 +2279,14 @@ Srdjan Petrovic <spetrovic@google.com>
|
||||||
Sridhar Venkatakrishnan <sridhar@laddoo.net>
|
Sridhar Venkatakrishnan <sridhar@laddoo.net>
|
||||||
Srinidhi Kaushik <shrinidhi.kaushik@gmail.com>
|
Srinidhi Kaushik <shrinidhi.kaushik@gmail.com>
|
||||||
StalkR <stalkr@stalkr.net>
|
StalkR <stalkr@stalkr.net>
|
||||||
|
Stan Hu <stanhu@gmail.com>
|
||||||
Stan Schwertly <stan@schwertly.com>
|
Stan Schwertly <stan@schwertly.com>
|
||||||
Stanislav Afanasev <php.progger@gmail.com>
|
Stanislav Afanasev <php.progger@gmail.com>
|
||||||
Steeve Morin <steeve.morin@gmail.com>
|
Steeve Morin <steeve.morin@gmail.com>
|
||||||
Stefan Baebler <sbaebler@outbrain.com>
|
Stefan Baebler <sbaebler@outbrain.com>
|
||||||
Stefan Nilsson <snilsson@nada.kth.se> <trolleriprofessorn@gmail.com>
|
Stefan Nilsson <snilsson@nada.kth.se> <trolleriprofessorn@gmail.com>
|
||||||
Stepan Shabalin <neverliberty@gmail.com>
|
Stepan Shabalin <neverliberty@gmail.com>
|
||||||
|
Stephan Klatt <stephan.klatt@gmail.com>
|
||||||
Stephan Renatus <srenatus@chef.io>
|
Stephan Renatus <srenatus@chef.io>
|
||||||
Stephan Zuercher <zuercher@gmail.com>
|
Stephan Zuercher <zuercher@gmail.com>
|
||||||
Stéphane Travostino <stephane.travostino@gmail.com>
|
Stéphane Travostino <stephane.travostino@gmail.com>
|
||||||
|
@ -2163,13 +2304,16 @@ Steve Mynott <steve.mynott@gmail.com>
|
||||||
Steve Newman <snewman@google.com>
|
Steve Newman <snewman@google.com>
|
||||||
Steve Phillips <elimisteve@gmail.com>
|
Steve Phillips <elimisteve@gmail.com>
|
||||||
Steve Streeting <steve@stevestreeting.com>
|
Steve Streeting <steve@stevestreeting.com>
|
||||||
|
Steve Traut <straut@google.com>
|
||||||
Steven Buss <sbuss@google.com>
|
Steven Buss <sbuss@google.com>
|
||||||
Steven Elliot Harris <seharris@gmail.com>
|
Steven Elliot Harris <seharris@gmail.com>
|
||||||
Steven Erenst <stevenerenst@gmail.com>
|
Steven Erenst <stevenerenst@gmail.com>
|
||||||
Steven Hartland <steven.hartland@multiplay.co.uk>
|
Steven Hartland <steven.hartland@multiplay.co.uk>
|
||||||
Steven Littiebrant <imgroxx@gmail.com>
|
Steven Littiebrant <imgroxx@gmail.com>
|
||||||
|
Steven Maude <git@stevenmaude.co.uk>
|
||||||
Steven Wilkin <stevenwilkin@gmail.com>
|
Steven Wilkin <stevenwilkin@gmail.com>
|
||||||
Stuart Jansen <sjansen@buscaluz.org>
|
Stuart Jansen <sjansen@buscaluz.org>
|
||||||
|
Subham Sarkar <sarkar.subhams2@gmail.com>
|
||||||
Sue Spence <virtuallysue@gmail.com>
|
Sue Spence <virtuallysue@gmail.com>
|
||||||
Sugu Sougoumarane <ssougou@gmail.com>
|
Sugu Sougoumarane <ssougou@gmail.com>
|
||||||
Suharsh Sivakumar <suharshs@google.com>
|
Suharsh Sivakumar <suharshs@google.com>
|
||||||
|
@ -2193,6 +2337,7 @@ Taesu Pyo <pyotaesu@gmail.com>
|
||||||
Tai Le <letientai299@gmail.com>
|
Tai Le <letientai299@gmail.com>
|
||||||
Taj Khattra <taj.khattra@gmail.com>
|
Taj Khattra <taj.khattra@gmail.com>
|
||||||
Takashi Matsuo <tmatsuo@google.com>
|
Takashi Matsuo <tmatsuo@google.com>
|
||||||
|
Takashi Mima <tks.m1205@gmail.com>
|
||||||
Takayoshi Nishida <takayoshi.nishida@gmail.com>
|
Takayoshi Nishida <takayoshi.nishida@gmail.com>
|
||||||
Takeshi YAMANASHI <9.nashi@gmail.com>
|
Takeshi YAMANASHI <9.nashi@gmail.com>
|
||||||
Takuto Ikuta <tikuta@google.com>
|
Takuto Ikuta <tikuta@google.com>
|
||||||
|
@ -2221,6 +2366,7 @@ Thanatat Tamtan <acoshift@gmail.com>
|
||||||
The Hatsune Daishi <nao20010128@gmail.com>
|
The Hatsune Daishi <nao20010128@gmail.com>
|
||||||
Thiago Avelino <t@avelino.xxx>
|
Thiago Avelino <t@avelino.xxx>
|
||||||
Thiago Fransosi Farina <thiago.farina@gmail.com> <tfarina@chromium.org>
|
Thiago Fransosi Farina <thiago.farina@gmail.com> <tfarina@chromium.org>
|
||||||
|
Thom Wiggers <thom@thomwiggers.nl>
|
||||||
Thomas Alan Copeland <talan.copeland@gmail.com>
|
Thomas Alan Copeland <talan.copeland@gmail.com>
|
||||||
Thomas Bonfort <thomas.bonfort@gmail.com>
|
Thomas Bonfort <thomas.bonfort@gmail.com>
|
||||||
Thomas Bouldin <inlined@google.com>
|
Thomas Bouldin <inlined@google.com>
|
||||||
|
@ -2245,6 +2391,7 @@ Tim Ebringer <tim.ebringer@gmail.com>
|
||||||
Tim Heckman <t@heckman.io>
|
Tim Heckman <t@heckman.io>
|
||||||
Tim Henderson <tim.tadh@gmail.com>
|
Tim Henderson <tim.tadh@gmail.com>
|
||||||
Tim Hockin <thockin@google.com>
|
Tim Hockin <thockin@google.com>
|
||||||
|
Tim King <taking@google.com>
|
||||||
Tim Möhlmann <muhlemmer@gmail.com>
|
Tim Möhlmann <muhlemmer@gmail.com>
|
||||||
Tim Swast <swast@google.com>
|
Tim Swast <swast@google.com>
|
||||||
Tim Wright <tenortim@gmail.com>
|
Tim Wright <tenortim@gmail.com>
|
||||||
|
@ -2252,8 +2399,10 @@ Tim Xu <xiaoxubeii@gmail.com>
|
||||||
Timmy Douglas <timmyd983@gmail.com>
|
Timmy Douglas <timmyd983@gmail.com>
|
||||||
Timo Savola <timo.savola@gmail.com>
|
Timo Savola <timo.savola@gmail.com>
|
||||||
Timo Truyts <alkaloid.btx@gmail.com>
|
Timo Truyts <alkaloid.btx@gmail.com>
|
||||||
|
Timothy Gu <timothygu99@gmail.com>
|
||||||
Timothy Studd <tim@timstudd.com>
|
Timothy Studd <tim@timstudd.com>
|
||||||
Tipp Moseley <tipp@google.com>
|
Tipp Moseley <tipp@google.com>
|
||||||
|
Tiwei Bie <tiwei.btw@antgroup.com>
|
||||||
Tobias Assarsson <tobias.assarsson@gmail.com>
|
Tobias Assarsson <tobias.assarsson@gmail.com>
|
||||||
Tobias Columbus <tobias.columbus@gmail.com> <tobias.columbus@googlemail.com>
|
Tobias Columbus <tobias.columbus@gmail.com> <tobias.columbus@googlemail.com>
|
||||||
Tobias Klauser <tklauser@distanz.ch>
|
Tobias Klauser <tklauser@distanz.ch>
|
||||||
|
@ -2268,11 +2417,13 @@ Tom Lanyon <tomlanyon@google.com>
|
||||||
Tom Levy <tomlevy93@gmail.com>
|
Tom Levy <tomlevy93@gmail.com>
|
||||||
Tom Limoncelli <tal@whatexit.org>
|
Tom Limoncelli <tal@whatexit.org>
|
||||||
Tom Linford <tomlinford@gmail.com>
|
Tom Linford <tomlinford@gmail.com>
|
||||||
|
Tom Panton <tom@tomandtally.co.uk>
|
||||||
Tom Parkin <tom.parkin@gmail.com>
|
Tom Parkin <tom.parkin@gmail.com>
|
||||||
Tom Payne <twpayne@gmail.com>
|
Tom Payne <twpayne@gmail.com>
|
||||||
Tom Szymanski <tgs@google.com>
|
Tom Szymanski <tgs@google.com>
|
||||||
Tom Thorogood <me+google@tomthorogood.co.uk>
|
Tom Thorogood <me+google@tomthorogood.co.uk>
|
||||||
Tom Wilkie <tom@weave.works>
|
Tom Wilkie <tom@weave.works>
|
||||||
|
Tom Zierbock <tomzierbock@gmail.com>
|
||||||
Tomas Dabasinskas <tomas@dabasinskas.net>
|
Tomas Dabasinskas <tomas@dabasinskas.net>
|
||||||
Tommy Schaefer <tommy.schaefer@teecom.com>
|
Tommy Schaefer <tommy.schaefer@teecom.com>
|
||||||
Tomohiro Kusumoto <zabio1192@gmail.com>
|
Tomohiro Kusumoto <zabio1192@gmail.com>
|
||||||
|
@ -2298,6 +2449,7 @@ Tristan Colgate <tcolgate@gmail.com>
|
||||||
Tristan Ooohry <ooohry@gmail.com>
|
Tristan Ooohry <ooohry@gmail.com>
|
||||||
Tristan Rice <rice@fn.lc>
|
Tristan Rice <rice@fn.lc>
|
||||||
Troels Thomsen <troels@thomsen.io>
|
Troels Thomsen <troels@thomsen.io>
|
||||||
|
Trong Bui <trong.buiquoc@gmail.com>
|
||||||
Trung Nguyen <trung.n.k@gmail.com>
|
Trung Nguyen <trung.n.k@gmail.com>
|
||||||
Tsuji Daishiro <dram.dt.shonan@gmail.com>
|
Tsuji Daishiro <dram.dt.shonan@gmail.com>
|
||||||
Tudor Golubenco <tudor.g@gmail.com>
|
Tudor Golubenco <tudor.g@gmail.com>
|
||||||
|
@ -2308,6 +2460,7 @@ Tyler Bunnell <tylerbunnell@gmail.com>
|
||||||
Tyler Treat <ttreat31@gmail.com>
|
Tyler Treat <ttreat31@gmail.com>
|
||||||
Tyson Andre <tysonandre775@gmail.com>
|
Tyson Andre <tysonandre775@gmail.com>
|
||||||
Tzach Shabtay <tzachshabtay@gmail.com>
|
Tzach Shabtay <tzachshabtay@gmail.com>
|
||||||
|
Tzu-Chiao Yeh <su3g4284zo6y7@gmail.com>
|
||||||
Tzu-Jung Lee <roylee17@currant.com>
|
Tzu-Jung Lee <roylee17@currant.com>
|
||||||
Udalov Max <re.udalov@gmail.com>
|
Udalov Max <re.udalov@gmail.com>
|
||||||
Ugorji Nwoke <ugorji@gmail.com>
|
Ugorji Nwoke <ugorji@gmail.com>
|
||||||
|
@ -2316,6 +2469,7 @@ Ulrich Kunitz <uli.kunitz@gmail.com>
|
||||||
Umang Parmar <umangjparmar@gmail.com>
|
Umang Parmar <umangjparmar@gmail.com>
|
||||||
Uriel Mangado <uriel@berlinblue.org>
|
Uriel Mangado <uriel@berlinblue.org>
|
||||||
Urvil Patel <patelurvil38@gmail.com>
|
Urvil Patel <patelurvil38@gmail.com>
|
||||||
|
Utkarsh Dixit <53217283+utkarsh-extc@users.noreply.github.com>
|
||||||
Uttam C Pawar <uttam.c.pawar@intel.com>
|
Uttam C Pawar <uttam.c.pawar@intel.com>
|
||||||
Vadim Grek <vadimprog@gmail.com>
|
Vadim Grek <vadimprog@gmail.com>
|
||||||
Vadim Vygonets <unixdj@gmail.com>
|
Vadim Vygonets <unixdj@gmail.com>
|
||||||
|
@ -2327,6 +2481,7 @@ Venil Noronha <veniln@vmware.com>
|
||||||
Veselkov Konstantin <kostozyb@gmail.com>
|
Veselkov Konstantin <kostozyb@gmail.com>
|
||||||
Viacheslav Poturaev <vearutop@gmail.com>
|
Viacheslav Poturaev <vearutop@gmail.com>
|
||||||
Victor Chudnovsky <vchudnov@google.com>
|
Victor Chudnovsky <vchudnov@google.com>
|
||||||
|
Victor Michel <victor@optimyze.cloud>
|
||||||
Victor Vrantchan <vrancean+github@gmail.com>
|
Victor Vrantchan <vrancean+github@gmail.com>
|
||||||
Vignesh Ramachandra <vickyramachandra@gmail.com>
|
Vignesh Ramachandra <vickyramachandra@gmail.com>
|
||||||
Vikas Kedia <vikask@google.com>
|
Vikas Kedia <vikask@google.com>
|
||||||
|
@ -2341,6 +2496,7 @@ Visweswara R <r.visweswara@gmail.com>
|
||||||
Vitaly Zdanevich <zdanevich.vitaly@ya.ru>
|
Vitaly Zdanevich <zdanevich.vitaly@ya.ru>
|
||||||
Vitor De Mario <vitordemario@gmail.com>
|
Vitor De Mario <vitordemario@gmail.com>
|
||||||
Vivek Sekhar <vsekhar@google.com>
|
Vivek Sekhar <vsekhar@google.com>
|
||||||
|
Vivek V <iamvivekv96@gmail.com>
|
||||||
Vivian Liang <vliang88@gmail.com>
|
Vivian Liang <vliang88@gmail.com>
|
||||||
Vlad Krasnov <vlad@cloudflare.com>
|
Vlad Krasnov <vlad@cloudflare.com>
|
||||||
Vladimir Evgrafov <evgrafov.vladimir@gmail.com>
|
Vladimir Evgrafov <evgrafov.vladimir@gmail.com>
|
||||||
|
@ -2392,6 +2548,7 @@ Wu Yunzhou <yunzhouwu@gmail.com>
|
||||||
Xi Ruoyao <xry23333@gmail.com>
|
Xi Ruoyao <xry23333@gmail.com>
|
||||||
Xia Bin <snyh@snyh.org>
|
Xia Bin <snyh@snyh.org>
|
||||||
Xiangdong Ji <xiangdong.ji@arm.com>
|
Xiangdong Ji <xiangdong.ji@arm.com>
|
||||||
|
Xiaodong Liu <teaofmoli@gmail.com>
|
||||||
Xing Xing <mikespook@gmail.com>
|
Xing Xing <mikespook@gmail.com>
|
||||||
Xingqang Bai <bxq2011hust@qq.com>
|
Xingqang Bai <bxq2011hust@qq.com>
|
||||||
Xu Fei <badgangkiller@gmail.com>
|
Xu Fei <badgangkiller@gmail.com>
|
||||||
|
@ -2459,6 +2616,7 @@ Zhou Peng <p@ctriple.cn>
|
||||||
Ziad Hatahet <hatahet@gmail.com>
|
Ziad Hatahet <hatahet@gmail.com>
|
||||||
Ziheng Liu <lzhfromustc@gmail.com>
|
Ziheng Liu <lzhfromustc@gmail.com>
|
||||||
Zorion Arrizabalaga <zorionk@gmail.com>
|
Zorion Arrizabalaga <zorionk@gmail.com>
|
||||||
|
Zyad A. Ali <zyad.ali.me@gmail.com>
|
||||||
Максадбек Ахмедов <a.maksadbek@gmail.com>
|
Максадбек Ахмедов <a.maksadbek@gmail.com>
|
||||||
Максим Федосеев <max.faceless.frei@gmail.com>
|
Максим Федосеев <max.faceless.frei@gmail.com>
|
||||||
Роман Хавроненко <hagen1778@gmail.com>
|
Роман Хавроненко <hagen1778@gmail.com>
|
||||||
|
|
12
README.md
|
@ -3,7 +3,7 @@
|
||||||
Go is an open source programming language that makes it easy to build simple,
|
Go is an open source programming language that makes it easy to build simple,
|
||||||
reliable, and efficient software.
|
reliable, and efficient software.
|
||||||
|
|
||||||
![Gopher image](doc/gopher/fiveyears.jpg)
|
![Gopher image](https://golang.org/doc/gopher/fiveyears.jpg)
|
||||||
*Gopher image by [Renee French][rf], licensed under [Creative Commons 3.0 Attributions license][cc3-by].*
|
*Gopher image by [Renee French][rf], licensed under [Creative Commons 3.0 Attributions license][cc3-by].*
|
||||||
|
|
||||||
Our canonical Git repository is located at https://go.googlesource.com/go.
|
Our canonical Git repository is located at https://go.googlesource.com/go.
|
||||||
|
@ -19,22 +19,20 @@ BSD-style license found in the LICENSE file.
|
||||||
Official binary distributions are available at https://golang.org/dl/.
|
Official binary distributions are available at https://golang.org/dl/.
|
||||||
|
|
||||||
After downloading a binary release, visit https://golang.org/doc/install
|
After downloading a binary release, visit https://golang.org/doc/install
|
||||||
or load [doc/install.html](./doc/install.html) in your web browser for installation
|
for installation instructions.
|
||||||
instructions.
|
|
||||||
|
|
||||||
#### Install From Source
|
#### Install From Source
|
||||||
|
|
||||||
If a binary distribution is not available for your combination of
|
If a binary distribution is not available for your combination of
|
||||||
operating system and architecture, visit
|
operating system and architecture, visit
|
||||||
https://golang.org/doc/install/source or load [doc/install-source.html](./doc/install-source.html)
|
https://golang.org/doc/install/source
|
||||||
in your web browser for source installation instructions.
|
for source installation instructions.
|
||||||
|
|
||||||
### Contributing
|
### Contributing
|
||||||
|
|
||||||
Go is the work of thousands of contributors. We appreciate your help!
|
Go is the work of thousands of contributors. We appreciate your help!
|
||||||
|
|
||||||
To contribute, please read the contribution guidelines:
|
To contribute, please read the contribution guidelines at https://golang.org/doc/contribute.html.
|
||||||
https://golang.org/doc/contribute.html
|
|
||||||
|
|
||||||
Note that the Go project uses the issue tracker for bug reports and
|
Note that the Go project uses the issue tracker for bug reports and
|
||||||
proposals only. See https://golang.org/wiki/Questions for a list of
|
proposals only. See https://golang.org/wiki/Questions for a list of
|
||||||
|
|
|
@ -1,254 +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 a 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 Go example programs are obtained by running</p>
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
git clone https://github.com/golang/example
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>and thus the import path for the root directory of that repository is
|
|
||||||
"<code>github.com/golang/example</code>".
|
|
||||||
The <a href="https://godoc.org/github.com/golang/example/stringutil">stringutil</a>
|
|
||||||
package is stored in a subdirectory, so its import path is
|
|
||||||
"<code>github.com/golang/example/stringutil</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
|
|
||||||
<code>$GOPATH/src/<import-path></code>.
|
|
||||||
If unset, <code>$GOPATH</code> defaults to a subdirectory
|
|
||||||
named <code>go</code> in the user's home directory.
|
|
||||||
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 toolchain.</p>
|
|
||||||
|
|
||||||
<h2>Getting started with the go command</h2>
|
|
||||||
|
|
||||||
<p>Finally, a quick tour of how to use the go command.
|
|
||||||
As mentioned above, the default <code>$GOPATH</code> on Unix is <code>$HOME/go</code>.
|
|
||||||
We'll store our programs there.
|
|
||||||
To use a different location, you can set <code>$GOPATH</code>;
|
|
||||||
see <a href="/doc/code.html">How to Write Go Code</a> for details.
|
|
||||||
|
|
||||||
<p>We first 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 github.com/google/codesearch/index
|
|
||||||
$ go get github.com/petar/GoLLRB/llrb
|
|
||||||
$
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>Both of these projects are now downloaded and installed into <code>$HOME/go</code>,
|
|
||||||
which contains the two directories
|
|
||||||
<code>src/github.com/google/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>
|
|
||||||
$ cd $HOME/go/src
|
|
||||||
$ go list ./...
|
|
||||||
github.com/google/codesearch/cmd/cgrep
|
|
||||||
github.com/google/codesearch/cmd/cindex
|
|
||||||
github.com/google/codesearch/cmd/csearch
|
|
||||||
github.com/google/codesearch/index
|
|
||||||
github.com/google/codesearch/regexp
|
|
||||||
github.com/google/codesearch/sparse
|
|
||||||
github.com/petar/GoLLRB/example
|
|
||||||
github.com/petar/GoLLRB/llrb
|
|
||||||
$
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>We can also test those packages:</p>
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
$ go test ./...
|
|
||||||
? github.com/google/codesearch/cmd/cgrep [no test files]
|
|
||||||
? github.com/google/codesearch/cmd/cindex [no test files]
|
|
||||||
? github.com/google/codesearch/cmd/csearch [no test files]
|
|
||||||
ok github.com/google/codesearch/index 0.203s
|
|
||||||
ok github.com/google/codesearch/regexp 0.017s
|
|
||||||
? github.com/google/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 github.com/google/codesearch/regexp
|
|
||||||
$ go list
|
|
||||||
github.com/google/codesearch/regexp
|
|
||||||
$ go test -v
|
|
||||||
=== RUN TestNstateEnc
|
|
||||||
--- PASS: TestNstateEnc (0.00s)
|
|
||||||
=== RUN TestMatch
|
|
||||||
--- PASS: TestMatch (0.00s)
|
|
||||||
=== RUN TestGrep
|
|
||||||
--- PASS: TestGrep (0.00s)
|
|
||||||
PASS
|
|
||||||
ok github.com/google/codesearch/regexp 0.018s
|
|
||||||
$ 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>
|
|
||||||
|
|
||||||
<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 <em>during</em> a build, although it does provide
|
|
||||||
<a href="/cmd/go/#hdr-Generate_Go_files_by_processing_source"><code>go</code>
|
|
||||||
<code>generate</code></a>,
|
|
||||||
which can automate the creation of Go files <em>before</em> the build.
|
|
||||||
For more advanced build setups, you may need to write a
|
|
||||||
makefile (or a configuration file for the build tool of your choice)
|
|
||||||
to run whatever tool creates 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,440 +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>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
<code>atexit_sleep_ms</code> (default <code>1000</code>): Amount of milliseconds
|
|
||||||
to sleep in the main goroutine before exiting.
|
|
||||||
</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>
|
|
||||||
|
|
||||||
<h3 id="Unsynchronized_send_and_close_operations">Unsynchronized send and close operations</h3>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
As this example demonstrates, unsynchronized send and close operations
|
|
||||||
on the same channel can also be a race condition:
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
c := make(chan struct{}) // or buffered channel
|
|
||||||
|
|
||||||
// The race detector cannot derive the happens before relation
|
|
||||||
// for the following send and close operations. These two operations
|
|
||||||
// are unsynchronized and happen concurrently.
|
|
||||||
go func() { c <- struct{}{} }()
|
|
||||||
close(c)
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
According to the Go memory model, a send on a channel happens before
|
|
||||||
the corresponding receive from that channel completes. To synchronize
|
|
||||||
send and close operations, use a receive operation that guarantees
|
|
||||||
the send is done before the close:
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
c := make(chan struct{}) // or buffered channel
|
|
||||||
|
|
||||||
go func() { c <- struct{}{} }()
|
|
||||||
<-c
|
|
||||||
close(c)
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<h2 id="Supported_Systems">Supported Systems</h2>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
The race detector runs on
|
|
||||||
<code>linux/amd64</code>, <code>linux/ppc64le</code>,
|
|
||||||
<code>linux/arm64</code>, <code>freebsd/amd64</code>,
|
|
||||||
<code>netbsd/amd64</code>, <code>darwin/amd64</code>,
|
|
||||||
<code>darwin/arm64</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>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
The race detector currently allocates an extra 8 bytes per <code>defer</code>
|
|
||||||
and <code>recover</code> statement. Those extra allocations <a
|
|
||||||
href="https://golang.org/issue/26813">are not recovered until the goroutine
|
|
||||||
exits</a>. This means that if you have a long-running goroutine that is
|
|
||||||
periodically issuing <code>defer</code> and <code>recover</code> calls,
|
|
||||||
the program memory usage may grow without bound. These memory allocations
|
|
||||||
will not show up in the output of <code>runtime.ReadMemStats</code> or
|
|
||||||
<code>runtime/pprof</code>.
|
|
||||||
</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,105 +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.
|
|
||||||
|
|
||||||
// +build ignore
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"html/template"
|
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
|
||||||
"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)
|
|
||||||
log.Fatal(http.ListenAndServe(":8080", nil))
|
|
||||||
}
|
|
|
@ -1,56 +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.
|
|
||||||
|
|
||||||
// +build ignore
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"html/template"
|
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
|
||||||
"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)
|
|
||||||
log.Fatal(http.ListenAndServe(":8080", nil))
|
|
||||||
}
|
|
|
@ -1,94 +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.
|
|
||||||
|
|
||||||
// +build ignore
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"html/template"
|
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
|
||||||
"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))
|
|
||||||
log.Fatal(http.ListenAndServe(":8080", nil))
|
|
||||||
}
|
|
|
@ -1,68 +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.
|
|
||||||
|
|
||||||
// +build ignore
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"html/template"
|
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
|
||||||
"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)
|
|
||||||
log.Fatal(http.ListenAndServe(":8080", nil))
|
|
||||||
}
|
|
|
@ -1,92 +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.
|
|
||||||
|
|
||||||
// +build ignore
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"html/template"
|
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
|
||||||
"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)
|
|
||||||
}
|
|
||||||
|
|
||||||
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() {
|
|
||||||
http.HandleFunc("/view/", makeHandler(viewHandler))
|
|
||||||
http.HandleFunc("/edit/", makeHandler(editHandler))
|
|
||||||
http.HandleFunc("/save/", makeHandler(saveHandler))
|
|
||||||
|
|
||||||
log.Fatal(http.ListenAndServe(":8080", nil))
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
// Copyright 2019 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.
|
|
||||||
|
|
||||||
// +build ignore
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
"net"
|
|
||||||
"net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
func serve() error {
|
|
||||||
l, err := net.Listen("tcp", "127.0.0.1:0")
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
fmt.Println(l.Addr().String())
|
|
||||||
s := &http.Server{}
|
|
||||||
return s.Serve(l)
|
|
||||||
}
|
|
|
@ -1,3 +0,0 @@
|
||||||
module doc/articles/wiki
|
|
||||||
|
|
||||||
go 1.14
|
|
|
@ -1,18 +0,0 @@
|
||||||
// +build ignore
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
"net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
func handler(w http.ResponseWriter, r *http.Request) {
|
|
||||||
fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:])
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
http.HandleFunc("/", handler)
|
|
||||||
log.Fatal(http.ListenAndServe(":8080", nil))
|
|
||||||
}
|
|
|
@ -1,741 +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>
|
|
||||||
<code>ListenAndServe</code> always returns an error, since it only returns when an
|
|
||||||
unexpected error occurs.
|
|
||||||
In order to log that error we wrap the function call with <code>log.Fatal</code>.
|
|
||||||
</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"
|
|
||||||
"log"
|
|
||||||
<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>
|
|
||||||
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>
|
|
||||||
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>
|
|
||||||
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>validPath</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,59 +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.
|
|
||||||
|
|
||||||
// +build ignore
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
|
||||||
"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 editHandler(w http.ResponseWriter, r *http.Request) {
|
|
||||||
title := r.URL.Path[len("/edit/"):]
|
|
||||||
p, err := loadPage(title)
|
|
||||||
if err != nil {
|
|
||||||
p = &Page{Title: title}
|
|
||||||
}
|
|
||||||
fmt.Fprintf(w, "<h1>Editing %s</h1>"+
|
|
||||||
"<form action=\"/save/%s\" method=\"POST\">"+
|
|
||||||
"<textarea name=\"body\">%s</textarea><br>"+
|
|
||||||
"<input type=\"submit\" value=\"Save\">"+
|
|
||||||
"</form>",
|
|
||||||
p.Title, p.Title, p.Body)
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
http.HandleFunc("/view/", viewHandler)
|
|
||||||
http.HandleFunc("/edit/", editHandler)
|
|
||||||
log.Fatal(http.ListenAndServe(":8080", nil))
|
|
||||||
}
|
|
|
@ -1,35 +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.
|
|
||||||
|
|
||||||
// +build ignore
|
|
||||||
|
|
||||||
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,38 +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.
|
|
||||||
|
|
||||||
// +build ignore
|
|
||||||
|
|
||||||
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,44 +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.
|
|
||||||
|
|
||||||
// +build ignore
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
|
||||||
"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)
|
|
||||||
log.Fatal(http.ListenAndServe(":8080", nil))
|
|
||||||
}
|
|
|
@ -1,76 +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.
|
|
||||||
|
|
||||||
// +build ignore
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"html/template"
|
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
|
||||||
"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)
|
|
||||||
log.Fatal(http.ListenAndServe(":8080", nil))
|
|
||||||
}
|
|
|
@ -1,60 +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.
|
|
||||||
|
|
||||||
// +build ignore
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"html/template"
|
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
|
||||||
"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)
|
|
||||||
log.Fatal(http.ListenAndServe(":8080", nil))
|
|
||||||
}
|
|
|
@ -1 +0,0 @@
|
||||||
some content
|
|
|
@ -1,6 +0,0 @@
|
||||||
<h1>Editing Test</h1>
|
|
||||||
|
|
||||||
<form action="/save/Test" method="POST">
|
|
||||||
<div><textarea name="body" rows="20" cols="80"></textarea></div>
|
|
||||||
<div><input type="submit" value="Save"></div>
|
|
||||||
</form>
|
|
|
@ -1,5 +0,0 @@
|
||||||
<h1>Test</h1>
|
|
||||||
|
|
||||||
<p>[<a href="/edit/Test">edit</a>]</p>
|
|
||||||
|
|
||||||
<div>some content</div>
|
|
|
@ -1,5 +0,0 @@
|
||||||
<h1>{{.Title}}</h1>
|
|
||||||
|
|
||||||
<p>[<a href="/edit/{{.Title}}">edit</a>]</p>
|
|
||||||
|
|
||||||
<div>{{printf "%s" .Body}}</div>
|
|
|
@ -1,165 +0,0 @@
|
||||||
// Copyright 2019 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_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestSnippetsCompile(t *testing.T) {
|
|
||||||
if testing.Short() {
|
|
||||||
t.Skip("skipping slow builds in short mode")
|
|
||||||
}
|
|
||||||
|
|
||||||
goFiles, err := filepath.Glob("*.go")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, f := range goFiles {
|
|
||||||
if strings.HasSuffix(f, "_test.go") {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
f := f
|
|
||||||
t.Run(f, func(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
cmd := exec.Command("go", "build", "-o", os.DevNull, f)
|
|
||||||
out, err := cmd.CombinedOutput()
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("%s: %v\n%s", strings.Join(cmd.Args, " "), err, out)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestWikiServer(t *testing.T) {
|
|
||||||
must := func(err error) {
|
|
||||||
if err != nil {
|
|
||||||
t.Helper()
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dir, err := ioutil.TempDir("", t.Name())
|
|
||||||
must(err)
|
|
||||||
defer os.RemoveAll(dir)
|
|
||||||
|
|
||||||
// We're testing a walkthrough example of how to write a server.
|
|
||||||
//
|
|
||||||
// That server hard-codes a port number to make the walkthrough simpler, but
|
|
||||||
// we can't assume that the hard-coded port is available on an arbitrary
|
|
||||||
// builder. So we'll patch out the hard-coded port, and replace it with a
|
|
||||||
// function that writes the server's address to stdout
|
|
||||||
// so that we can read it and know where to send the test requests.
|
|
||||||
|
|
||||||
finalGo, err := ioutil.ReadFile("final.go")
|
|
||||||
must(err)
|
|
||||||
const patchOld = `log.Fatal(http.ListenAndServe(":8080", nil))`
|
|
||||||
patched := bytes.ReplaceAll(finalGo, []byte(patchOld), []byte(`log.Fatal(serve())`))
|
|
||||||
if bytes.Equal(patched, finalGo) {
|
|
||||||
t.Fatalf("Can't patch final.go: %q not found.", patchOld)
|
|
||||||
}
|
|
||||||
must(ioutil.WriteFile(filepath.Join(dir, "final_patched.go"), patched, 0644))
|
|
||||||
|
|
||||||
// Build the server binary from the patched sources.
|
|
||||||
// The 'go' command requires that they all be in the same directory.
|
|
||||||
// final_test.go provides the implemtation for our serve function.
|
|
||||||
must(copyFile(filepath.Join(dir, "final_srv.go"), "final_test.go"))
|
|
||||||
cmd := exec.Command("go", "build",
|
|
||||||
"-o", filepath.Join(dir, "final.exe"),
|
|
||||||
filepath.Join(dir, "final_patched.go"),
|
|
||||||
filepath.Join(dir, "final_srv.go"))
|
|
||||||
out, err := cmd.CombinedOutput()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("%s: %v\n%s", strings.Join(cmd.Args, " "), err, out)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run the server in our temporary directory so that it can
|
|
||||||
// write its content there. It also needs a couple of template files,
|
|
||||||
// and looks for them in the same directory.
|
|
||||||
must(copyFile(filepath.Join(dir, "edit.html"), "edit.html"))
|
|
||||||
must(copyFile(filepath.Join(dir, "view.html"), "view.html"))
|
|
||||||
cmd = exec.Command(filepath.Join(dir, "final.exe"))
|
|
||||||
cmd.Dir = dir
|
|
||||||
stderr := bytes.NewBuffer(nil)
|
|
||||||
cmd.Stderr = stderr
|
|
||||||
stdout, err := cmd.StdoutPipe()
|
|
||||||
must(err)
|
|
||||||
must(cmd.Start())
|
|
||||||
|
|
||||||
defer func() {
|
|
||||||
cmd.Process.Kill()
|
|
||||||
err := cmd.Wait()
|
|
||||||
if stderr.Len() > 0 {
|
|
||||||
t.Logf("%s: %v\n%s", strings.Join(cmd.Args, " "), err, stderr)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
var addr string
|
|
||||||
if _, err := fmt.Fscanln(stdout, &addr); err != nil || addr == "" {
|
|
||||||
t.Fatalf("Failed to read server address: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// The server is up and has told us its address.
|
|
||||||
// Make sure that its HTTP API works as described in the article.
|
|
||||||
|
|
||||||
r, err := http.Get(fmt.Sprintf("http://%s/edit/Test", addr))
|
|
||||||
must(err)
|
|
||||||
responseMustMatchFile(t, r, "test_edit.good")
|
|
||||||
|
|
||||||
r, err = http.Post(fmt.Sprintf("http://%s/save/Test", addr),
|
|
||||||
"application/x-www-form-urlencoded",
|
|
||||||
strings.NewReader("body=some%20content"))
|
|
||||||
must(err)
|
|
||||||
responseMustMatchFile(t, r, "test_view.good")
|
|
||||||
|
|
||||||
gotTxt, err := ioutil.ReadFile(filepath.Join(dir, "Test.txt"))
|
|
||||||
must(err)
|
|
||||||
wantTxt, err := ioutil.ReadFile("test_Test.txt.good")
|
|
||||||
must(err)
|
|
||||||
if !bytes.Equal(wantTxt, gotTxt) {
|
|
||||||
t.Fatalf("Test.txt differs from expected after posting to /save.\ngot:\n%s\nwant:\n%s", gotTxt, wantTxt)
|
|
||||||
}
|
|
||||||
|
|
||||||
r, err = http.Get(fmt.Sprintf("http://%s/view/Test", addr))
|
|
||||||
must(err)
|
|
||||||
responseMustMatchFile(t, r, "test_view.good")
|
|
||||||
}
|
|
||||||
|
|
||||||
func responseMustMatchFile(t *testing.T, r *http.Response, filename string) {
|
|
||||||
t.Helper()
|
|
||||||
|
|
||||||
defer r.Body.Close()
|
|
||||||
body, err := ioutil.ReadAll(r.Body)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
wantBody, err := ioutil.ReadFile(filename)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !bytes.Equal(body, wantBody) {
|
|
||||||
t.Fatalf("%v: body does not match %s.\ngot:\n%s\nwant:\n%s", r.Request.URL, filename, body, wantBody)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func copyFile(dst, src string) error {
|
|
||||||
buf, err := ioutil.ReadFile(src)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return ioutil.WriteFile(dst, buf, 0644)
|
|
||||||
}
|
|
100
doc/cmd.html
|
@ -1,100 +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 cgo</code>.
|
|
||||||
For most commands this is mainly useful for debugging.
|
|
||||||
Some of the commands, such as <code>pprof</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.
|
|
||||||
</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="/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/gofmt/">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/golang.org/x/tools/cmd/godoc/">godoc</a></td>
|
|
||||||
<td> </td>
|
|
||||||
<td>Godoc extracts and generates documentation for Go packages.</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td><a href="/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>
|
|
||||||
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
This is an abridged list. See the <a href="/cmd/">full command reference</a>
|
|
||||||
for documentation of the compilers and more.
|
|
||||||
</p>
|
|
|
@ -1,234 +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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#codewalk-main {
|
|
||||||
text-align: left;
|
|
||||||
width: 100%;
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
#code-display {
|
|
||||||
border: 0;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.setting {
|
|
||||||
font-size: 8pt;
|
|
||||||
color: #888888;
|
|
||||||
padding: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hotkey {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Style for Comments (the left-hand column) */
|
|
||||||
|
|
||||||
#comment-column {
|
|
||||||
margin: 0pt;
|
|
||||||
width: 30%;
|
|
||||||
}
|
|
||||||
|
|
||||||
#comment-column.right {
|
|
||||||
float: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
#comment-column.left {
|
|
||||||
float: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
#comment-area {
|
|
||||||
overflow-x: hidden;
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.comment {
|
|
||||||
cursor: pointer;
|
|
||||||
font-size: 16px;
|
|
||||||
border: 2px solid #ba9836;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
margin-right: 10px; /* yes, for both .left and .right */
|
|
||||||
}
|
|
||||||
|
|
||||||
.comment:last-child {
|
|
||||||
margin-bottom: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.right .comment {
|
|
||||||
margin-left: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.right .comment.first {
|
|
||||||
}
|
|
||||||
|
|
||||||
.right .comment.last {
|
|
||||||
}
|
|
||||||
|
|
||||||
.left .comment.first {
|
|
||||||
}
|
|
||||||
|
|
||||||
.left .comment.last {
|
|
||||||
}
|
|
||||||
|
|
||||||
.comment.selected {
|
|
||||||
border-color: #99b2cb;
|
|
||||||
}
|
|
||||||
|
|
||||||
.right .comment.selected {
|
|
||||||
border-left-width: 12px;
|
|
||||||
margin-left: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.left .comment.selected {
|
|
||||||
border-right-width: 12px;
|
|
||||||
margin-right: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.comment-link {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.comment-title {
|
|
||||||
font-size: small;
|
|
||||||
font-weight: bold;
|
|
||||||
background-color: #fffff0;
|
|
||||||
padding-right: 10px;
|
|
||||||
padding-left: 10px;
|
|
||||||
padding-top: 5px;
|
|
||||||
padding-bottom: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.right .comment-title {
|
|
||||||
}
|
|
||||||
|
|
||||||
.left .comment-title {
|
|
||||||
}
|
|
||||||
|
|
||||||
.comment.selected .comment-title {
|
|
||||||
background-color: #f8f8ff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.comment-text {
|
|
||||||
overflow: auto;
|
|
||||||
padding-left: 10px;
|
|
||||||
padding-right: 10px;
|
|
||||||
padding-top: 10px;
|
|
||||||
padding-bottom: 5px;
|
|
||||||
font-size: small;
|
|
||||||
line-height: 1.3em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.comment-text p {
|
|
||||||
margin-top: 0em;
|
|
||||||
margin-bottom: 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.comment-text p:last-child {
|
|
||||||
margin-bottom: 0em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.file-name {
|
|
||||||
font-size: x-small;
|
|
||||||
padding-top: 0px;
|
|
||||||
padding-bottom: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hidden-filepaths .file-name {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.path-dir {
|
|
||||||
color: #555;
|
|
||||||
}
|
|
||||||
|
|
||||||
.path-file {
|
|
||||||
color: #555;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Style for Code (the right-hand column) */
|
|
||||||
|
|
||||||
/* Wrapper for the code column to make widths get calculated correctly */
|
|
||||||
#code-column {
|
|
||||||
display: block;
|
|
||||||
position: relative;
|
|
||||||
margin: 0pt;
|
|
||||||
width: 70%;
|
|
||||||
}
|
|
||||||
|
|
||||||
#code-column.left {
|
|
||||||
float: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
#code-column.right {
|
|
||||||
float: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
#code-area {
|
|
||||||
background-color: #f8f8ff;
|
|
||||||
border: 2px solid #99b2cb;
|
|
||||||
padding: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.left #code-area {
|
|
||||||
margin-right: -1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.right #code-area {
|
|
||||||
margin-left: -1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#code-header {
|
|
||||||
margin-bottom: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#code {
|
|
||||||
background-color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
code {
|
|
||||||
font-size: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.codewalkhighlight {
|
|
||||||
font-weight: bold;
|
|
||||||
background-color: #f8f8ff;
|
|
||||||
}
|
|
||||||
|
|
||||||
#code-display {
|
|
||||||
margin-top: 0px;
|
|
||||||
margin-bottom: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#sizer {
|
|
||||||
position: absolute;
|
|
||||||
cursor: col-resize;
|
|
||||||
left: 0px;
|
|
||||||
top: 0px;
|
|
||||||
width: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Style for options (bottom strip) */
|
|
||||||
|
|
||||||
#code-options {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#code-options > span {
|
|
||||||
padding-right: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#code-options .selected {
|
|
||||||
border-bottom: 1px dotted;
|
|
||||||
}
|
|
||||||
|
|
||||||
#comment-options {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
div#content {
|
|
||||||
padding-bottom: 0em;
|
|
||||||
}
|
|
|
@ -1,305 +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.
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A class to hold information about the Codewalk Viewer.
|
|
||||||
* @param {jQuery} context The top element in whose context the viewer should
|
|
||||||
* operate. It will not touch any elements above this one.
|
|
||||||
* @constructor
|
|
||||||
*/
|
|
||||||
var CodewalkViewer = function(context) {
|
|
||||||
this.context = context;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The div that contains all of the comments and their controls.
|
|
||||||
*/
|
|
||||||
this.commentColumn = this.context.find('#comment-column');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The div that contains the comments proper.
|
|
||||||
*/
|
|
||||||
this.commentArea = this.context.find('#comment-area');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The div that wraps the iframe with the code, as well as the drop down menu
|
|
||||||
* listing the different files.
|
|
||||||
* @type {jQuery}
|
|
||||||
*/
|
|
||||||
this.codeColumn = this.context.find('#code-column');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The div that contains the code but excludes the options strip.
|
|
||||||
* @type {jQuery}
|
|
||||||
*/
|
|
||||||
this.codeArea = this.context.find('#code-area');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The iframe that holds the code (from Sourcerer).
|
|
||||||
* @type {jQuery}
|
|
||||||
*/
|
|
||||||
this.codeDisplay = this.context.find('#code-display');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The overlaid div used as a grab handle for sizing the code/comment panes.
|
|
||||||
* @type {jQuery}
|
|
||||||
*/
|
|
||||||
this.sizer = this.context.find('#sizer');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The full-screen overlay that ensures we don't lose track of the mouse
|
|
||||||
* while dragging.
|
|
||||||
* @type {jQuery}
|
|
||||||
*/
|
|
||||||
this.overlay = this.context.find('#overlay');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The hidden input field that we use to hold the focus so that we can detect
|
|
||||||
* shortcut keypresses.
|
|
||||||
* @type {jQuery}
|
|
||||||
*/
|
|
||||||
this.shortcutInput = this.context.find('#shortcut-input');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The last comment that was selected.
|
|
||||||
* @type {jQuery}
|
|
||||||
*/
|
|
||||||
this.lastSelected = null;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Minimum width of the comments or code pane, in pixels.
|
|
||||||
* @type {number}
|
|
||||||
*/
|
|
||||||
CodewalkViewer.MIN_PANE_WIDTH = 200;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Navigate the code iframe to the given url and update the code popout link.
|
|
||||||
* @param {string} url The target URL.
|
|
||||||
* @param {Object} opt_window Window dependency injection for testing only.
|
|
||||||
*/
|
|
||||||
CodewalkViewer.prototype.navigateToCode = function(url, opt_window) {
|
|
||||||
if (!opt_window) opt_window = window;
|
|
||||||
// Each iframe is represented by two distinct objects in the DOM: an iframe
|
|
||||||
// object and a window object. These do not expose the same capabilities.
|
|
||||||
// Here we need to get the window representation to get the location member,
|
|
||||||
// so we access it directly through window[] since jQuery returns the iframe
|
|
||||||
// representation.
|
|
||||||
// We replace location rather than set so as not to create a history for code
|
|
||||||
// navigation.
|
|
||||||
opt_window['code-display'].location.replace(url);
|
|
||||||
var k = url.indexOf('&');
|
|
||||||
if (k != -1) url = url.slice(0, k);
|
|
||||||
k = url.indexOf('fileprint=');
|
|
||||||
if (k != -1) url = url.slice(k+10, url.length);
|
|
||||||
this.context.find('#code-popout-link').attr('href', url);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Selects the first comment from the list and forces a refresh of the code
|
|
||||||
* view.
|
|
||||||
*/
|
|
||||||
CodewalkViewer.prototype.selectFirstComment = function() {
|
|
||||||
// TODO(rsc): handle case where there are no comments
|
|
||||||
var firstSourcererLink = this.context.find('.comment:first');
|
|
||||||
this.changeSelectedComment(firstSourcererLink);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the target on all links nested inside comments to be _blank.
|
|
||||||
*/
|
|
||||||
CodewalkViewer.prototype.targetCommentLinksAtBlank = function() {
|
|
||||||
this.context.find('.comment a[href], #description a[href]').each(function() {
|
|
||||||
if (!this.target) this.target = '_blank';
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Installs event handlers for all the events we care about.
|
|
||||||
*/
|
|
||||||
CodewalkViewer.prototype.installEventHandlers = function() {
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
this.context.find('.comment')
|
|
||||||
.click(function(event) {
|
|
||||||
if (jQuery(event.target).is('a[href]')) return true;
|
|
||||||
self.changeSelectedComment(jQuery(this));
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
this.context.find('#code-selector')
|
|
||||||
.change(function() {self.navigateToCode(jQuery(this).val());});
|
|
||||||
|
|
||||||
this.context.find('#description-table .quote-feet.setting')
|
|
||||||
.click(function() {self.toggleDescription(jQuery(this)); return false;});
|
|
||||||
|
|
||||||
this.sizer
|
|
||||||
.mousedown(function(ev) {self.startSizerDrag(ev); return false;});
|
|
||||||
this.overlay
|
|
||||||
.mouseup(function(ev) {self.endSizerDrag(ev); return false;})
|
|
||||||
.mousemove(function(ev) {self.handleSizerDrag(ev); return false;});
|
|
||||||
|
|
||||||
this.context.find('#prev-comment')
|
|
||||||
.click(function() {
|
|
||||||
self.changeSelectedComment(self.lastSelected.prev()); return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
this.context.find('#next-comment')
|
|
||||||
.click(function() {
|
|
||||||
self.changeSelectedComment(self.lastSelected.next()); return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Workaround for Firefox 2 and 3, which steal focus from the main document
|
|
||||||
// whenever the iframe content is (re)loaded. The input field is not shown,
|
|
||||||
// but is a way for us to bring focus back to a place where we can detect
|
|
||||||
// keypresses.
|
|
||||||
this.context.find('#code-display')
|
|
||||||
.load(function(ev) {self.shortcutInput.focus();});
|
|
||||||
|
|
||||||
jQuery(document).keypress(function(ev) {
|
|
||||||
switch(ev.which) {
|
|
||||||
case 110: // 'n'
|
|
||||||
self.changeSelectedComment(self.lastSelected.next());
|
|
||||||
return false;
|
|
||||||
case 112: // 'p'
|
|
||||||
self.changeSelectedComment(self.lastSelected.prev());
|
|
||||||
return false;
|
|
||||||
default: // ignore
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
window.onresize = function() {self.updateHeight();};
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Starts dragging the pane sizer.
|
|
||||||
* @param {Object} ev The mousedown event that started us dragging.
|
|
||||||
*/
|
|
||||||
CodewalkViewer.prototype.startSizerDrag = function(ev) {
|
|
||||||
this.initialCodeWidth = this.codeColumn.width();
|
|
||||||
this.initialCommentsWidth = this.commentColumn.width();
|
|
||||||
this.initialMouseX = ev.pageX;
|
|
||||||
this.overlay.show();
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles dragging the pane sizer.
|
|
||||||
* @param {Object} ev The mousemove event updating dragging position.
|
|
||||||
*/
|
|
||||||
CodewalkViewer.prototype.handleSizerDrag = function(ev) {
|
|
||||||
var delta = ev.pageX - this.initialMouseX;
|
|
||||||
if (this.codeColumn.is('.right')) delta = -delta;
|
|
||||||
var proposedCodeWidth = this.initialCodeWidth + delta;
|
|
||||||
var proposedCommentWidth = this.initialCommentsWidth - delta;
|
|
||||||
var mw = CodewalkViewer.MIN_PANE_WIDTH;
|
|
||||||
if (proposedCodeWidth < mw) delta = mw - this.initialCodeWidth;
|
|
||||||
if (proposedCommentWidth < mw) delta = this.initialCommentsWidth - mw;
|
|
||||||
proposedCodeWidth = this.initialCodeWidth + delta;
|
|
||||||
proposedCommentWidth = this.initialCommentsWidth - delta;
|
|
||||||
// If window is too small, don't even try to resize.
|
|
||||||
if (proposedCodeWidth < mw || proposedCommentWidth < mw) return;
|
|
||||||
this.codeColumn.width(proposedCodeWidth);
|
|
||||||
this.commentColumn.width(proposedCommentWidth);
|
|
||||||
this.options.codeWidth = parseInt(
|
|
||||||
this.codeColumn.width() /
|
|
||||||
(this.codeColumn.width() + this.commentColumn.width()) * 100);
|
|
||||||
this.context.find('#code-column-width').text(this.options.codeWidth + '%');
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ends dragging the pane sizer.
|
|
||||||
* @param {Object} ev The mouseup event that caused us to stop dragging.
|
|
||||||
*/
|
|
||||||
CodewalkViewer.prototype.endSizerDrag = function(ev) {
|
|
||||||
this.overlay.hide();
|
|
||||||
this.updateHeight();
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Toggles the Codewalk description between being shown and hidden.
|
|
||||||
* @param {jQuery} target The target that was clicked to trigger this function.
|
|
||||||
*/
|
|
||||||
CodewalkViewer.prototype.toggleDescription = function(target) {
|
|
||||||
var description = this.context.find('#description');
|
|
||||||
description.toggle();
|
|
||||||
target.find('span').text(description.is(':hidden') ? 'show' : 'hide');
|
|
||||||
this.updateHeight();
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Changes the side of the window on which the code is shown and saves the
|
|
||||||
* setting in a cookie.
|
|
||||||
* @param {string?} codeSide The side on which the code should be, either
|
|
||||||
* 'left' or 'right'.
|
|
||||||
*/
|
|
||||||
CodewalkViewer.prototype.changeCodeSide = function(codeSide) {
|
|
||||||
var commentSide = codeSide == 'left' ? 'right' : 'left';
|
|
||||||
this.context.find('#set-code-' + codeSide).addClass('selected');
|
|
||||||
this.context.find('#set-code-' + commentSide).removeClass('selected');
|
|
||||||
// Remove previous side class and add new one.
|
|
||||||
this.codeColumn.addClass(codeSide).removeClass(commentSide);
|
|
||||||
this.commentColumn.addClass(commentSide).removeClass(codeSide);
|
|
||||||
this.sizer.css(codeSide, 'auto').css(commentSide, 0);
|
|
||||||
this.options.codeSide = codeSide;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds selected class to newly selected comment, removes selected style from
|
|
||||||
* previously selected comment, changes drop down options so that the correct
|
|
||||||
* file is selected, and updates the code popout link.
|
|
||||||
* @param {jQuery} target The target that was clicked to trigger this function.
|
|
||||||
*/
|
|
||||||
CodewalkViewer.prototype.changeSelectedComment = function(target) {
|
|
||||||
var currentFile = target.find('.comment-link').attr('href');
|
|
||||||
if (!currentFile) return;
|
|
||||||
|
|
||||||
if (!(this.lastSelected && this.lastSelected.get(0) === target.get(0))) {
|
|
||||||
if (this.lastSelected) this.lastSelected.removeClass('selected');
|
|
||||||
target.addClass('selected');
|
|
||||||
this.lastSelected = target;
|
|
||||||
var targetTop = target.position().top;
|
|
||||||
var parentTop = target.parent().position().top;
|
|
||||||
if (targetTop + target.height() > parentTop + target.parent().height() ||
|
|
||||||
targetTop < parentTop) {
|
|
||||||
var delta = targetTop - parentTop;
|
|
||||||
target.parent().animate(
|
|
||||||
{'scrollTop': target.parent().scrollTop() + delta},
|
|
||||||
Math.max(delta / 2, 200), 'swing');
|
|
||||||
}
|
|
||||||
var fname = currentFile.match(/(?:select=|fileprint=)\/[^&]+/)[0];
|
|
||||||
fname = fname.slice(fname.indexOf('=')+2, fname.length);
|
|
||||||
this.context.find('#code-selector').val(fname);
|
|
||||||
this.context.find('#prev-comment').toggleClass(
|
|
||||||
'disabled', !target.prev().length);
|
|
||||||
this.context.find('#next-comment').toggleClass(
|
|
||||||
'disabled', !target.next().length);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Force original file even if user hasn't changed comments since they may
|
|
||||||
// have navigated away from it within the iframe without us knowing.
|
|
||||||
this.navigateToCode(currentFile);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the viewer by changing the height of the comments and code so that
|
|
||||||
* they fit within the height of the window. The function is typically called
|
|
||||||
* after the user changes the window size.
|
|
||||||
*/
|
|
||||||
CodewalkViewer.prototype.updateHeight = function() {
|
|
||||||
var windowHeight = jQuery(window).height() - 5 // GOK
|
|
||||||
var areaHeight = windowHeight - this.codeArea.offset().top
|
|
||||||
var footerHeight = this.context.find('#footer').outerHeight(true)
|
|
||||||
this.commentArea.height(areaHeight - footerHeight - this.context.find('#comment-options').outerHeight(true))
|
|
||||||
var codeHeight = areaHeight - footerHeight - 15 // GOK
|
|
||||||
this.codeArea.height(codeHeight)
|
|
||||||
this.codeDisplay.height(codeHeight - this.codeDisplay.offset().top + this.codeArea.offset().top);
|
|
||||||
this.sizer.height(codeHeight);
|
|
||||||
};
|
|
||||||
|
|
||||||
window.initFuncs.push(function() {
|
|
||||||
var viewer = new CodewalkViewer(jQuery('#codewalk-main'));
|
|
||||||
viewer.selectFirstComment();
|
|
||||||
viewer.targetCommentLinksAtBlank();
|
|
||||||
viewer.installEventHandlers();
|
|
||||||
viewer.updateHeight();
|
|
||||||
});
|
|
|
@ -1,124 +0,0 @@
|
||||||
<codewalk title="How to Write a Codewalk">
|
|
||||||
|
|
||||||
<step title="Introduction" src="doc/codewalk/codewalk.xml">
|
|
||||||
A codewalk is a guided tour through a piece of code.
|
|
||||||
It consists of a sequence of steps, each typically explaining
|
|
||||||
a highlighted section of code.
|
|
||||||
<br/><br/>
|
|
||||||
|
|
||||||
The <a href="/cmd/godoc">godoc</a> web server translates
|
|
||||||
an XML file like the one in the main window pane into the HTML
|
|
||||||
page that you're viewing now.
|
|
||||||
<br/><br/>
|
|
||||||
|
|
||||||
The codewalk with URL path <code>/doc/codewalk/</code><i>name</i>
|
|
||||||
is loaded from the input file <code>$GOROOT/doc/codewalk/</code><i>name</i><code>.xml</code>.
|
|
||||||
<br/><br/>
|
|
||||||
|
|
||||||
This codewalk explains how to write a codewalk by examining
|
|
||||||
its own source code,
|
|
||||||
<code><a href="/doc/codewalk/codewalk.xml">$GOROOT/doc/codewalk/codewalk.xml</a></code>,
|
|
||||||
shown in the main window pane to the left.
|
|
||||||
</step>
|
|
||||||
|
|
||||||
<step title="Title" src="doc/codewalk/codewalk.xml:/title=/">
|
|
||||||
The codewalk input file is an XML file containing a single
|
|
||||||
<code><codewalk></code> element.
|
|
||||||
That element's <code>title</code> attribute gives the title
|
|
||||||
that is used both on the codewalk page and in the codewalk list.
|
|
||||||
</step>
|
|
||||||
|
|
||||||
<step title="Steps" src="doc/codewalk/codewalk.xml:/<step/,/step>/">
|
|
||||||
Each step in the codewalk is a <code><step></code> element
|
|
||||||
nested inside the main <code><codewalk></code>.
|
|
||||||
The step element's <code>title</code> attribute gives the step's title,
|
|
||||||
which is shown in a shaded bar above the main step text.
|
|
||||||
The element's <code>src</code> attribute specifies the source
|
|
||||||
code to show in the main window pane and, optionally, a range of
|
|
||||||
lines to highlight.
|
|
||||||
<br/><br/>
|
|
||||||
|
|
||||||
The first step in this codewalk does not highlight any lines:
|
|
||||||
its <code>src</code> is just a file name.
|
|
||||||
</step>
|
|
||||||
|
|
||||||
<step title="Specifying 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,
|
|
||||||
the codewalk uses an address syntax that makes it possible
|
|
||||||
to describe the match by its content.
|
|
||||||
As the file gets edited, this descriptive address has a better
|
|
||||||
chance to continue to refer to the right section of the file.
|
|
||||||
<br/><br/>
|
|
||||||
|
|
||||||
To specify a source line, use a <code>src</code> attribute of the form
|
|
||||||
<i>filename</i><code>:</code><i>address</i>,
|
|
||||||
where <i>address</i> is an address in the syntax used by the text editors <i>sam</i> and <i>acme</i>.
|
|
||||||
<br/><br/>
|
|
||||||
|
|
||||||
The simplest address is a single regular expression.
|
|
||||||
The highlighted line in the main window pane shows that the
|
|
||||||
address for the “Title” step was <code>/title=/</code>,
|
|
||||||
which matches the first instance of that <a href="/pkg/regexp">regular expression</a> (<code>title=</code>) in the file.
|
|
||||||
</step>
|
|
||||||
|
|
||||||
<step title="Specifying a source range" src='doc/codewalk/codewalk.xml:/title="Steps"/'>
|
|
||||||
To highlight a range of source lines, the simplest address to use is
|
|
||||||
a pair of regular expressions
|
|
||||||
<code>/</code><i>regexp1</i><code>/,/</code><i>regexp2</i><code>/</code>.
|
|
||||||
The highlight begins with the line containing the first match for <i>regexp1</i>
|
|
||||||
and ends with the line containing the first match for <i>regexp2</i>
|
|
||||||
after the end of the match for <i>regexp1</i>.
|
|
||||||
Ignoring the HTML quoting,
|
|
||||||
The line containing the first match for <i>regexp1</i> will be the first one highlighted,
|
|
||||||
and the line containing the first match for <i>regexp2</i>.
|
|
||||||
<br/><br/>
|
|
||||||
|
|
||||||
The address <code>/<step/,/step>/</code> looks for the first instance of
|
|
||||||
<code><step</code> in the file, and then starting after that point,
|
|
||||||
looks for the first instance of <code>step></code>.
|
|
||||||
(Click on the “Steps” step above to see the highlight in action.)
|
|
||||||
Note that the <code><</code> and <code>></code> had to be written
|
|
||||||
using XML escapes in order to be valid XML.
|
|
||||||
</step>
|
|
||||||
|
|
||||||
<step title="Advanced addressing" src="doc/codewalk/codewalk.xml:/Advanced/,/step>/">
|
|
||||||
The <code>/</code><i>regexp</i><code>/</code>
|
|
||||||
and <code>/</code><i>regexp1</i><code>/,/</code><i>regexp2</i><code>/</code>
|
|
||||||
forms suffice for most highlighting.
|
|
||||||
<br/><br/>
|
|
||||||
|
|
||||||
The full address syntax is summarized in this table
|
|
||||||
(an excerpt of Table II from
|
|
||||||
<a href="https://9p.io/sys/doc/sam/sam.html">The text editor <code>sam</code></a>):
|
|
||||||
<br/><br/>
|
|
||||||
|
|
||||||
<table>
|
|
||||||
<tr><td colspan="2"><b>Simple addresses</b></td></tr>
|
|
||||||
<tr><td><code>#</code><i>n</i></td>
|
|
||||||
<td>The empty string after character <i>n</i></td></tr>
|
|
||||||
<tr><td><i>n</i></td>
|
|
||||||
<td>Line <i>n</i></td></tr>
|
|
||||||
<tr><td><code>/</code><i>regexp</i><code>/</code></td>
|
|
||||||
<td>The first following match of the regular expression</td></tr>
|
|
||||||
<!-- not supported (yet?)
|
|
||||||
<tr><td><code>–/</code><i>regexp</i><code>/</code></td>
|
|
||||||
<td>The first previous match of the regular expression</td></tr>
|
|
||||||
-->
|
|
||||||
<tr><td><code>$</code></td>
|
|
||||||
<td>The null string at the end of the file</td></tr>
|
|
||||||
|
|
||||||
<tr><td colspan="2"><b>Compound addresses</b></td></tr>
|
|
||||||
<tr><td><i>a1</i><code>+</code><i>a2</i></td>
|
|
||||||
<td>The address <i>a2</i> evaluated starting at the right of <i>a1</i></td></tr>
|
|
||||||
<tr><td><i>a1</i><code>-</code><i>a2</i></td>
|
|
||||||
<td>The address <i>a2</i> evaluated in the reverse direction starting at the left of <i>a1</i></td></tr>
|
|
||||||
<tr><td><i>a1</i><code>,</code><i>a2</i></td>
|
|
||||||
<td>From the left of <i>a1</i> to the right of <i>a2</i> (default <code>0,$</code>).</td></tr>
|
|
||||||
</table>
|
|
||||||
</step>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</codewalk>
|
|
|
@ -1,52 +0,0 @@
|
||||||
// Copyright 2019 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_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
// TestMarkov tests the code dependency of markov.xml.
|
|
||||||
func TestMarkov(t *testing.T) {
|
|
||||||
cmd := exec.Command("go", "run", "markov.go")
|
|
||||||
cmd.Stdin = strings.NewReader("foo")
|
|
||||||
cmd.Stderr = bytes.NewBuffer(nil)
|
|
||||||
out, err := cmd.Output()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("%s: %v\n%s", strings.Join(cmd.Args, " "), err, cmd.Stderr)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !bytes.Equal(out, []byte("foo\n")) {
|
|
||||||
t.Fatalf(`%s with input "foo" did not output "foo":\n%s`, strings.Join(cmd.Args, " "), out)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestPig tests the code dependency of functions.xml.
|
|
||||||
func TestPig(t *testing.T) {
|
|
||||||
cmd := exec.Command("go", "run", "pig.go")
|
|
||||||
cmd.Stderr = bytes.NewBuffer(nil)
|
|
||||||
out, err := cmd.Output()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("%s: %v\n%s", strings.Join(cmd.Args, " "), err, cmd.Stderr)
|
|
||||||
}
|
|
||||||
|
|
||||||
const want = "Wins, losses staying at k = 100: 210/990 (21.2%), 780/990 (78.8%)\n"
|
|
||||||
if !bytes.Contains(out, []byte(want)) {
|
|
||||||
t.Fatalf(`%s: unexpected output\ngot:\n%s\nwant output containing:\n%s`, strings.Join(cmd.Args, " "), out, want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestURLPoll tests the code dependency of sharemem.xml.
|
|
||||||
func TestURLPoll(t *testing.T) {
|
|
||||||
cmd := exec.Command("go", "build", "-o", os.DevNull, "urlpoll.go")
|
|
||||||
out, err := cmd.CombinedOutput()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("%s: %v\n%s", strings.Join(cmd.Args, " "), err, out)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,105 +0,0 @@
|
||||||
<codewalk title="First-Class Functions in Go">
|
|
||||||
|
|
||||||
<step title="Introduction" src="doc/codewalk/pig.go">
|
|
||||||
Go supports first class functions, higher-order functions, user-defined
|
|
||||||
function types, function literals, closures, and multiple return values.
|
|
||||||
<br/><br/>
|
|
||||||
|
|
||||||
This rich feature set supports a functional programming style in a strongly
|
|
||||||
typed language.
|
|
||||||
<br/><br/>
|
|
||||||
|
|
||||||
In this codewalk we will look at a simple program that simulates a dice game
|
|
||||||
called <a href="http://en.wikipedia.org/wiki/Pig_(dice)">Pig</a> and evaluates
|
|
||||||
basic strategies.
|
|
||||||
</step>
|
|
||||||
|
|
||||||
<step title="Game overview" src="doc/codewalk/pig.go:/\/\/ A score/,/thisTurn int\n}/">
|
|
||||||
Pig is a two-player game played with a 6-sided die. Each turn, you may roll or stay.
|
|
||||||
<ul>
|
|
||||||
<li> If you roll a 1, you lose all points for your turn and play passes to
|
|
||||||
your opponent. Any other roll adds its value to your turn score. </li>
|
|
||||||
<li> If you stay, your turn score is added to your total score, and play passes
|
|
||||||
to your opponent. </li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
The first person to reach 100 total points wins.
|
|
||||||
<br/><br/>
|
|
||||||
|
|
||||||
The <code>score</code> type stores the scores of the current and opposing
|
|
||||||
players, in addition to the points accumulated during the current turn.
|
|
||||||
</step>
|
|
||||||
|
|
||||||
<step title="User-defined function types" src="doc/codewalk/pig.go:/\/\/ An action/,/bool\)/">
|
|
||||||
In Go, functions can be passed around just like any other value. A function's
|
|
||||||
type signature describes the types of its arguments and return values.
|
|
||||||
<br/><br/>
|
|
||||||
|
|
||||||
The <code>action</code> type is a function that takes a <code>score</code>
|
|
||||||
and returns the resulting <code>score</code> and whether the current turn is
|
|
||||||
over.
|
|
||||||
<br/><br/>
|
|
||||||
|
|
||||||
If the turn is over, the <code>player</code> and <code>opponent</code> fields
|
|
||||||
in the resulting <code>score</code> should be swapped, as it is now the other player's
|
|
||||||
turn.
|
|
||||||
</step>
|
|
||||||
|
|
||||||
<step title="Multiple return values" src="doc/codewalk/pig.go:/\/\/ roll returns/,/true\n}/">
|
|
||||||
Go functions can return multiple values.
|
|
||||||
<br/><br/>
|
|
||||||
|
|
||||||
The functions <code>roll</code> and <code>stay</code> each return a pair of
|
|
||||||
values. They also match the <code>action</code> type signature. These
|
|
||||||
<code>action</code> functions define the rules of Pig.
|
|
||||||
</step>
|
|
||||||
|
|
||||||
<step title="Higher-order functions" src="doc/codewalk/pig.go:/\/\/ A strategy/,/action\n/">
|
|
||||||
A function can use other functions as arguments and return values.
|
|
||||||
<br/><br/>
|
|
||||||
|
|
||||||
A <code>strategy</code> is a function that takes a <code>score</code> as input
|
|
||||||
and returns an <code>action</code> to perform. <br/>
|
|
||||||
(Remember, an <code>action</code> is itself a function.)
|
|
||||||
</step>
|
|
||||||
|
|
||||||
<step title="Function literals and closures" src="doc/codewalk/pig.go:/return func/,/return roll\n\t}/">
|
|
||||||
Anonymous functions can be declared in Go, as in this example. Function
|
|
||||||
literals are closures: they inherit the scope of the function in which they
|
|
||||||
are declared.
|
|
||||||
<br/><br/>
|
|
||||||
|
|
||||||
One basic strategy in Pig is to continue rolling until you have accumulated at
|
|
||||||
least k points in a turn, and then stay. The argument <code>k</code> is
|
|
||||||
enclosed by this function literal, which matches the <code>strategy</code> type
|
|
||||||
signature.
|
|
||||||
</step>
|
|
||||||
|
|
||||||
<step title="Simulating games" src="doc/codewalk/pig.go:/\/\/ play/,/currentPlayer\n}/">
|
|
||||||
We simulate a game of Pig by calling an <code>action</code> to update the
|
|
||||||
<code>score</code> until one player reaches 100 points. Each
|
|
||||||
<code>action</code> is selected by calling the <code>strategy</code> function
|
|
||||||
associated with the current player.
|
|
||||||
</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.
|
|
||||||
</step>
|
|
||||||
|
|
||||||
<step title="Variadic function declarations" src="doc/codewalk/pig.go:/\/\/ ratioS/,/string {/">
|
|
||||||
Variadic functions like <code>ratioString</code> take a variable number of
|
|
||||||
arguments. These arguments are available as a slice inside the function.
|
|
||||||
</step>
|
|
||||||
|
|
||||||
<step title="Simulation results" src="doc/codewalk/pig.go:/func main/,/\n}/">
|
|
||||||
The <code>main</code> function defines 100 basic strategies, simulates a round
|
|
||||||
robin tournament, and then prints the win/loss record of each strategy.
|
|
||||||
<br/><br/>
|
|
||||||
|
|
||||||
Among these strategies, staying at 25 is best, but the <a
|
|
||||||
href="http://www.google.com/search?q=optimal+play+pig">optimal strategy for
|
|
||||||
Pig</a> is much more complex.
|
|
||||||
</step>
|
|
||||||
|
|
||||||
</codewalk>
|
|
|
@ -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>
|
|
|
@ -1,121 +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 (
|
|
||||||
"fmt"
|
|
||||||
"math/rand"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
win = 100 // The winning score in a game of Pig
|
|
||||||
gamesPerSeries = 10 // The number of games per series to simulate
|
|
||||||
)
|
|
||||||
|
|
||||||
// A score includes scores accumulated in previous turns for each player,
|
|
||||||
// as well as the points scored by the current player in this turn.
|
|
||||||
type score struct {
|
|
||||||
player, opponent, thisTurn int
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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.
|
|
||||||
// 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) {
|
|
||||||
outcome := rand.Intn(6) + 1 // A random int in [1, 6]
|
|
||||||
if outcome == 1 {
|
|
||||||
return score{s.opponent, s.player, 0}, true
|
|
||||||
}
|
|
||||||
return score{s.player, s.opponent, outcome + s.thisTurn}, false
|
|
||||||
}
|
|
||||||
|
|
||||||
// stay returns the (result, turnIsOver) outcome of staying.
|
|
||||||
// thisTurn score is added to the player's score, and the players' roles swap.
|
|
||||||
func stay(s score) (score, bool) {
|
|
||||||
return score{s.opponent, s.player + s.thisTurn, 0}, true
|
|
||||||
}
|
|
||||||
|
|
||||||
// A strategy chooses an action for any given score.
|
|
||||||
type strategy func(score) action
|
|
||||||
|
|
||||||
// stayAtK returns a strategy that rolls until thisTurn is at least k, then stays.
|
|
||||||
func stayAtK(k int) strategy {
|
|
||||||
return func(s score) action {
|
|
||||||
if s.thisTurn >= k {
|
|
||||||
return stay
|
|
||||||
}
|
|
||||||
return roll
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// play simulates a Pig game and returns the winner (0 or 1).
|
|
||||||
func play(strategy0, strategy1 strategy) int {
|
|
||||||
strategies := []strategy{strategy0, strategy1}
|
|
||||||
var s score
|
|
||||||
var turnIsOver bool
|
|
||||||
currentPlayer := rand.Intn(2) // Randomly decide who plays first
|
|
||||||
for s.player+s.thisTurn < win {
|
|
||||||
action := strategies[currentPlayer](s)
|
|
||||||
s, turnIsOver = action(s)
|
|
||||||
if turnIsOver {
|
|
||||||
currentPlayer = (currentPlayer + 1) % 2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return currentPlayer
|
|
||||||
}
|
|
||||||
|
|
||||||
// roundRobin simulates a series of games between every pair of strategies.
|
|
||||||
func roundRobin(strategies []strategy) ([]int, int) {
|
|
||||||
wins := make([]int, len(strategies))
|
|
||||||
for i := 0; i < len(strategies); i++ {
|
|
||||||
for j := i + 1; j < len(strategies); j++ {
|
|
||||||
for k := 0; k < gamesPerSeries; k++ {
|
|
||||||
winner := play(strategies[i], strategies[j])
|
|
||||||
if winner == 0 {
|
|
||||||
wins[i]++
|
|
||||||
} else {
|
|
||||||
wins[j]++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
gamesPerStrategy := gamesPerSeries * (len(strategies) - 1) // no self play
|
|
||||||
return wins, gamesPerStrategy
|
|
||||||
}
|
|
||||||
|
|
||||||
// ratioString takes a list of integer values and returns a string that lists
|
|
||||||
// each value and its percentage of the sum of all values.
|
|
||||||
// e.g., ratios(1, 2, 3) = "1/6 (16.7%), 2/6 (33.3%), 3/6 (50.0%)"
|
|
||||||
func ratioString(vals ...int) string {
|
|
||||||
total := 0
|
|
||||||
for _, val := range vals {
|
|
||||||
total += val
|
|
||||||
}
|
|
||||||
s := ""
|
|
||||||
for _, val := range vals {
|
|
||||||
if s != "" {
|
|
||||||
s += ", "
|
|
||||||
}
|
|
||||||
pct := 100 * float64(val) / float64(total)
|
|
||||||
s += fmt.Sprintf("%d/%d (%0.1f%%)", val, total, pct)
|
|
||||||
}
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
strategies := make([]strategy, win)
|
|
||||||
for k := range strategies {
|
|
||||||
strategies[k] = stayAtK(k + 1)
|
|
||||||
}
|
|
||||||
wins, games := roundRobin(strategies)
|
|
||||||
|
|
||||||
for k := range strategies {
|
|
||||||
fmt.Printf("Wins, losses staying at k =% 4d: %s\n",
|
|
||||||
k+1, ratioString(wins[k], games-wins[k]))
|
|
||||||
}
|
|
||||||
}
|
|
Двоичные данные
doc/codewalk/popout.png
До Ширина: | Высота: | Размер: 213 B |
|
@ -1,181 +0,0 @@
|
||||||
<codewalk title="Share Memory By Communicating">
|
|
||||||
|
|
||||||
<step title="Introduction" src="doc/codewalk/urlpoll.go">
|
|
||||||
Go's approach to concurrency differs from the traditional use of
|
|
||||||
threads and shared memory. Philosophically, it can be summarized:
|
|
||||||
<br/><br/>
|
|
||||||
<i>Don't communicate by sharing memory; share memory by communicating.</i>
|
|
||||||
<br/><br/>
|
|
||||||
Channels allow you to pass references to data structures between goroutines.
|
|
||||||
If you consider this as passing around ownership of the data (the ability to
|
|
||||||
read and write it), they become a powerful and expressive synchronization
|
|
||||||
mechanism.
|
|
||||||
<br/><br/>
|
|
||||||
In this codewalk we will look at a simple program that polls a list of
|
|
||||||
URLs, checking their HTTP response codes and periodically printing their state.
|
|
||||||
</step>
|
|
||||||
|
|
||||||
<step title="State type" src="doc/codewalk/urlpoll.go:/State/,/}/">
|
|
||||||
The State type represents the state of a URL.
|
|
||||||
<br/><br/>
|
|
||||||
The Pollers send State values to the StateMonitor,
|
|
||||||
which maintains a map of the current state of each URL.
|
|
||||||
</step>
|
|
||||||
|
|
||||||
<step title="Resource type" src="doc/codewalk/urlpoll.go:/Resource/,/}/">
|
|
||||||
A Resource represents the state of a URL to be polled: the URL itself
|
|
||||||
and the number of errors encountered since the last successful poll.
|
|
||||||
<br/><br/>
|
|
||||||
When the program starts, it allocates one Resource for each URL.
|
|
||||||
The main goroutine and the Poller goroutines send the Resources to
|
|
||||||
each other on channels.
|
|
||||||
</step>
|
|
||||||
|
|
||||||
<step title="Poller function" src="doc/codewalk/urlpoll.go:/func Poller/,/\n}/">
|
|
||||||
Each Poller receives Resource pointers from an input channel.
|
|
||||||
In this program, the convention is that sending a Resource pointer on
|
|
||||||
a channel passes ownership of the underlying data from the sender
|
|
||||||
to the receiver. Because of this convention, we know that
|
|
||||||
no two goroutines will access this Resource at the same time.
|
|
||||||
This means we don't have to worry about locking to prevent concurrent
|
|
||||||
access to these data structures.
|
|
||||||
<br/><br/>
|
|
||||||
The Poller processes the Resource by calling its Poll method.
|
|
||||||
<br/><br/>
|
|
||||||
It sends a State value to the status channel, to inform the StateMonitor
|
|
||||||
of the result of the Poll.
|
|
||||||
<br/><br/>
|
|
||||||
Finally, it sends the Resource pointer to the out channel. This can be
|
|
||||||
interpreted as the Poller saying "I'm done with this Resource" and
|
|
||||||
returning ownership of it to the main goroutine.
|
|
||||||
<br/><br/>
|
|
||||||
Several goroutines run Pollers, processing Resources in parallel.
|
|
||||||
</step>
|
|
||||||
|
|
||||||
<step title="The Poll method" src="doc/codewalk/urlpoll.go:/Poll executes/,/\n}/">
|
|
||||||
The Poll method (of the Resource type) performs an HTTP HEAD request
|
|
||||||
for the Resource's URL and returns the HTTP response's status code.
|
|
||||||
If an error occurs, Poll logs the message to standard error and returns the
|
|
||||||
error string instead.
|
|
||||||
</step>
|
|
||||||
|
|
||||||
<step title="main function" src="doc/codewalk/urlpoll.go:/func main/,/\n}/">
|
|
||||||
The main function starts the Poller and StateMonitor goroutines
|
|
||||||
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/">
|
|
||||||
First, main makes two channels of *Resource, pending and complete.
|
|
||||||
<br/><br/>
|
|
||||||
Inside main, a new goroutine sends one Resource per URL to pending
|
|
||||||
and the main goroutine receives completed Resources from complete.
|
|
||||||
<br/><br/>
|
|
||||||
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/">
|
|
||||||
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/>
|
|
||||||
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/,/}/">
|
|
||||||
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/,/}\(\)/">
|
|
||||||
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/>
|
|
||||||
The new goroutine is necessary because unbuffered channel sends and
|
|
||||||
receives are synchronous. That means these channel sends will block until
|
|
||||||
the Pollers are ready to read from pending.
|
|
||||||
<br/><br/>
|
|
||||||
Were these sends performed in the main goroutine with fewer Pollers than
|
|
||||||
channel sends, the program would reach a deadlock situation, because
|
|
||||||
main would not yet be receiving from complete.
|
|
||||||
<br/><br/>
|
|
||||||
Exercise for the reader: modify this part of the program to read a list of
|
|
||||||
URLs from a file. (You may want to move this goroutine into its own
|
|
||||||
named function.)
|
|
||||||
</step>
|
|
||||||
|
|
||||||
<step title="Main Event Loop" src="doc/codewalk/urlpoll.go:/range complete/,/\n }/">
|
|
||||||
When a Poller is done with a Resource, it sends it on the complete channel.
|
|
||||||
This loop receives those Resource pointers from complete.
|
|
||||||
For each received Resource, it starts a new goroutine calling
|
|
||||||
the Resource's Sleep method. Using a new goroutine for each
|
|
||||||
ensures that the sleeps can happen in parallel.
|
|
||||||
<br/><br/>
|
|
||||||
Note that any single Resource pointer may only be sent on either pending or
|
|
||||||
complete at any one time. This ensures that a Resource is either being
|
|
||||||
handled by a Poller goroutine or sleeping, but never both simultaneously.
|
|
||||||
In this way, we share our Resource data by communicating.
|
|
||||||
</step>
|
|
||||||
|
|
||||||
<step title="The Sleep method" src="doc/codewalk/urlpoll.go:/Sleep/,/\n}/">
|
|
||||||
Sleep calls time.Sleep to pause before sending the Resource to done.
|
|
||||||
The pause will either be of a fixed length (pollInterval) plus an
|
|
||||||
additional delay proportional to the number of sequential errors (r.errCount).
|
|
||||||
<br/><br/>
|
|
||||||
This is an example of a typical Go idiom: a function intended to run inside
|
|
||||||
a goroutine takes a channel, upon which it sends its return value
|
|
||||||
(or other indication of completed state).
|
|
||||||
</step>
|
|
||||||
|
|
||||||
<step title="StateMonitor" src="doc/codewalk/urlpoll.go:/StateMonitor/,/\n}/">
|
|
||||||
The StateMonitor receives State values on a channel and periodically
|
|
||||||
outputs the state of all Resources being polled by the program.
|
|
||||||
</step>
|
|
||||||
|
|
||||||
<step title="The updates channel" src="doc/codewalk/urlpoll.go:/updates :=/">
|
|
||||||
The variable updates is a channel of State, on which the Poller goroutines
|
|
||||||
send State values.
|
|
||||||
<br/><br/>
|
|
||||||
This channel is returned by the function.
|
|
||||||
</step>
|
|
||||||
|
|
||||||
<step title="The urlStatus map" src="doc/codewalk/urlpoll.go:/urlStatus/">
|
|
||||||
The variable urlStatus is a map of URLs to their most recent status.
|
|
||||||
</step>
|
|
||||||
|
|
||||||
<step title="The Ticker object" src="doc/codewalk/urlpoll.go:/ticker/">
|
|
||||||
A time.Ticker is an object that repeatedly sends a value on a channel at a
|
|
||||||
specified interval.
|
|
||||||
<br/><br/>
|
|
||||||
In this case, ticker triggers the printing of the current state to
|
|
||||||
standard output every updateInterval nanoseconds.
|
|
||||||
</step>
|
|
||||||
|
|
||||||
<step title="The StateMonitor goroutine" src="doc/codewalk/urlpoll.go:/go func/,/}\(\)/">
|
|
||||||
StateMonitor will loop forever, selecting on two channels:
|
|
||||||
ticker.C and update. The select statement blocks until one of its
|
|
||||||
communications is ready to proceed.
|
|
||||||
<br/><br/>
|
|
||||||
When StateMonitor receives a tick from ticker.C, it calls logState to
|
|
||||||
print the current state. When it receives a State update from updates,
|
|
||||||
it records the new status in the urlStatus map.
|
|
||||||
<br/><br/>
|
|
||||||
Notice that this goroutine owns the urlStatus data structure,
|
|
||||||
ensuring that it can only be accessed sequentially.
|
|
||||||
This prevents memory corruption issues that might arise from parallel reads
|
|
||||||
and/or writes to a shared map.
|
|
||||||
</step>
|
|
||||||
|
|
||||||
<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.
|
|
||||||
<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
|
|
||||||
programs.
|
|
||||||
</step>
|
|
||||||
|
|
||||||
</codewalk>
|
|
|
@ -1,116 +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 (
|
|
||||||
"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
|
|
||||||
)
|
|
||||||
|
|
||||||
var urls = []string{
|
|
||||||
"http://www.google.com/",
|
|
||||||
"http://golang.org/",
|
|
||||||
"http://blog.golang.org/",
|
|
||||||
}
|
|
||||||
|
|
||||||
// State represents the last-known state of a URL.
|
|
||||||
type State struct {
|
|
||||||
url string
|
|
||||||
status string
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 {
|
|
||||||
updates := make(chan State)
|
|
||||||
urlStatus := make(map[string]string)
|
|
||||||
ticker := time.NewTicker(updateInterval)
|
|
||||||
go func() {
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-ticker.C:
|
|
||||||
logState(urlStatus)
|
|
||||||
case s := <-updates:
|
|
||||||
urlStatus[s.url] = s.status
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
return updates
|
|
||||||
}
|
|
||||||
|
|
||||||
// logState prints a state map.
|
|
||||||
func logState(s map[string]string) {
|
|
||||||
log.Println("Current state:")
|
|
||||||
for k, v := range s {
|
|
||||||
log.Printf(" %s %s", k, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Resource represents an HTTP URL to be polled by this program.
|
|
||||||
type Resource struct {
|
|
||||||
url string
|
|
||||||
errCount int
|
|
||||||
}
|
|
||||||
|
|
||||||
// Poll executes an HTTP HEAD request for url
|
|
||||||
// and returns the HTTP status string or an error string.
|
|
||||||
func (r *Resource) Poll() string {
|
|
||||||
resp, err := http.Head(r.url)
|
|
||||||
if err != nil {
|
|
||||||
log.Println("Error", r.url, err)
|
|
||||||
r.errCount++
|
|
||||||
return err.Error()
|
|
||||||
}
|
|
||||||
r.errCount = 0
|
|
||||||
return resp.Status
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sleep sleeps for an appropriate interval (dependent on error state)
|
|
||||||
// before sending the Resource to done.
|
|
||||||
func (r *Resource) Sleep(done chan<- *Resource) {
|
|
||||||
time.Sleep(pollInterval + errTimeout*time.Duration(r.errCount))
|
|
||||||
done <- r
|
|
||||||
}
|
|
||||||
|
|
||||||
func Poller(in <-chan *Resource, out chan<- *Resource, status chan<- State) {
|
|
||||||
for r := range in {
|
|
||||||
s := r.Poll()
|
|
||||||
status <- State{r.url, s}
|
|
||||||
out <- r
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
// Create our input and output channels.
|
|
||||||
pending, complete := make(chan *Resource), make(chan *Resource)
|
|
||||||
|
|
||||||
// Launch the StateMonitor.
|
|
||||||
status := StateMonitor(statusInterval)
|
|
||||||
|
|
||||||
// Launch some Poller goroutines.
|
|
||||||
for i := 0; i < numPollers; i++ {
|
|
||||||
go Poller(pending, complete, status)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send some Resources to the pending queue.
|
|
||||||
go func() {
|
|
||||||
for _, url := range urls {
|
|
||||||
pending <- &Resource{url: url}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
for r := range complete {
|
|
||||||
go r.Sleep(pending)
|
|
||||||
}
|
|
||||||
}
|
|
1294
doc/contribute.html
|
@ -1,554 +0,0 @@
|
||||||
<!--{
|
|
||||||
"Title": "Debugging Go Code with GDB",
|
|
||||||
"Path": "/doc/gdb"
|
|
||||||
}-->
|
|
||||||
|
|
||||||
<!--
|
|
||||||
NOTE: In this document and others in this directory, the convention is to
|
|
||||||
set fixed-width phrases with non-fixed-width spaces, as in
|
|
||||||
<code>hello</code> <code>world</code>.
|
|
||||||
Do not send CLs removing the interior tags from such phrases.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<i>
|
|
||||||
<p>
|
|
||||||
The following instructions apply to the standard toolchain
|
|
||||||
(the <code>gc</code> Go compiler and tools).
|
|
||||||
Gccgo has native gdb support.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
Note that
|
|
||||||
<a href="https://github.com/go-delve/delve">Delve</a> is a better
|
|
||||||
alternative to GDB when debugging Go programs built with the standard
|
|
||||||
toolchain. It understands the Go runtime, data structures, and
|
|
||||||
expressions better than GDB. Delve currently supports Linux, OSX,
|
|
||||||
and Windows on <code>amd64</code>.
|
|
||||||
For the most up-to-date list of supported platforms, please see
|
|
||||||
<a href="https://github.com/go-delve/delve/tree/master/Documentation/installation">
|
|
||||||
the Delve documentation</a>.
|
|
||||||
</p>
|
|
||||||
</i>
|
|
||||||
|
|
||||||
<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 and cause incorrect results even when the program is
|
|
||||||
compiled with gccgo.
|
|
||||||
As a consequence, although GDB can be useful in some situations (e.g.,
|
|
||||||
debugging Cgo code, or debugging the runtime itself), 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.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
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.
|
|
||||||
|
|
||||||
Besides this overview you might want to consult the
|
|
||||||
<a href="https://sourceware.org/gdb/current/onlinedocs/gdb/">GDB manual</a>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h2 id="Introduction">Introduction</h2>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
When you compile and link your Go programs with the <code>gc</code> toolchain
|
|
||||||
on Linux, macOS, FreeBSD or NetBSD, the resulting binaries contain DWARFv4
|
|
||||||
debugging information that recent versions (≥7.5) 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</code> <code>build</code> <code>-ldflags=-w</code> <code>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.
|
|
||||||
If you find that you need to disable these optimizations,
|
|
||||||
build your program using <code>go</code> <code>build</code> <code>-gcflags=all="-N -l"</code>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
If you want to use gdb to inspect a core dump, you can trigger a dump
|
|
||||||
on a program crash, on systems that permit it, by setting
|
|
||||||
<code>GOTRACEBACK=crash</code> in the environment (see the
|
|
||||||
<a href="/pkg/runtime/#hdr-Environment_Variables"> runtime package
|
|
||||||
documentation</a> for more info).
|
|
||||||
</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 toolchain 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>
|
|
||||||
You can inspect all goroutines by passing <code>all</code> instead of a specific goroutine's ID.
|
|
||||||
For example:
|
|
||||||
<pre>(gdb) <b>goroutine all 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/link/internal/ld/dwarf.go">src/cmd/link/internal/ld/dwarf.go</a>) ensures are described in
|
|
||||||
the DWARF code.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
If you're interested in what the debugging information looks like, run
|
|
||||||
<code>objdump</code> <code>-W</code> <code>a.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>As of Go 1.11, debug information is compressed by default.
|
|
||||||
Older versions of gdb, such as the one available by default on MacOS,
|
|
||||||
do not understand the compression.
|
|
||||||
You can generate uncompressed debug information by using <code>go
|
|
||||||
build -ldflags=-compressdwarf=false</code>.
|
|
||||||
(For convenience you can put the <code>-ldflags</code> option in
|
|
||||||
the <a href="/cmd/go/#hdr-Environment_variables"><code>GOFLAGS</code>
|
|
||||||
environment variable</a> so that you don't have to specify it each time.)
|
|
||||||
</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</code> <code>test</code> <code>-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 "Loading Go Runtime support" 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 parameterizing <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</code> <code>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</code> <code>hchan<*testing.T></code> is the
|
|
||||||
runtime-internal representation of a channel. It is currently empty,
|
|
||||||
or gdb would have pretty-printed its 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>
|
|
|
@ -1,472 +0,0 @@
|
||||||
<!--{
|
|
||||||
"Title": "Diagnostics",
|
|
||||||
"Template": true
|
|
||||||
}-->
|
|
||||||
|
|
||||||
<!--
|
|
||||||
NOTE: In this document and others in this directory, the convention is to
|
|
||||||
set fixed-width phrases with non-fixed-width spaces, as in
|
|
||||||
<code>hello</code> <code>world</code>.
|
|
||||||
Do not send CLs removing the interior tags from such phrases.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<h2 id="introduction">Introduction</h2>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
The Go ecosystem provides a large suite of APIs and tools to
|
|
||||||
diagnose logic and performance problems in Go programs. This page
|
|
||||||
summarizes the available tools and helps Go users pick the right one
|
|
||||||
for their specific problem.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Diagnostics solutions can be categorized into the following groups:
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li><strong>Profiling</strong>: Profiling tools analyze the complexity and costs of a
|
|
||||||
Go program such as its memory usage and frequently called
|
|
||||||
functions to identify the expensive sections of a Go program.</li>
|
|
||||||
<li><strong>Tracing</strong>: Tracing is a way to instrument code to analyze latency
|
|
||||||
throughout the lifecycle of a call or user request. Traces provide an
|
|
||||||
overview of how much latency each component contributes to the overall
|
|
||||||
latency in a system. Traces can span multiple Go processes.</li>
|
|
||||||
<li><strong>Debugging</strong>: Debugging allows us to pause a Go program and examine
|
|
||||||
its execution. Program state and flow can be verified with debugging.</li>
|
|
||||||
<li><strong>Runtime statistics and events</strong>: Collection and analysis of runtime stats and events
|
|
||||||
provides a high-level overview of the health of Go programs. Spikes/dips of metrics
|
|
||||||
helps us to identify changes in throughput, utilization, and performance.</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Note: Some diagnostics tools may interfere with each other. For example, precise
|
|
||||||
memory profiling skews CPU profiles and goroutine blocking profiling affects scheduler
|
|
||||||
trace. Use tools in isolation to get more precise info.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h2 id="profiling">Profiling</h2>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Profiling is useful for identifying expensive or frequently called sections
|
|
||||||
of code. The Go runtime provides <a href="https://golang.org/pkg/runtime/pprof/">
|
|
||||||
profiling data</a> in the format expected by the
|
|
||||||
<a href="https://github.com/google/pprof/blob/master/doc/README.md">pprof visualization tool</a>.
|
|
||||||
The profiling data can be collected during testing
|
|
||||||
via <code>go</code> <code>test</code> or endpoints made available from the <a href="/pkg/net/http/pprof/">
|
|
||||||
net/http/pprof</a> package. Users need to collect the profiling data and use pprof tools to filter
|
|
||||||
and visualize the top code paths.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>Predefined profiles provided by the <a href="/pkg/runtime/pprof">runtime/pprof</a> package:</p>
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
<strong>cpu</strong>: CPU profile determines where a program spends
|
|
||||||
its time while actively consuming CPU cycles (as opposed to while sleeping or waiting for I/O).
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<strong>heap</strong>: Heap profile reports memory allocation samples;
|
|
||||||
used to monitor current and historical memory usage, and to check for memory leaks.
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<strong>threadcreate</strong>: Thread creation profile reports the sections
|
|
||||||
of the program that lead the creation of new OS threads.
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<strong>goroutine</strong>: Goroutine profile reports the stack traces of all current goroutines.
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<strong>block</strong>: Block profile shows where goroutines block waiting on synchronization
|
|
||||||
primitives (including timer channels). Block profile is not enabled by default;
|
|
||||||
use <code>runtime.SetBlockProfileRate</code> to enable it.
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<strong>mutex</strong>: Mutex profile reports the lock contentions. When you think your
|
|
||||||
CPU is not fully utilized due to a mutex contention, use this profile. Mutex profile
|
|
||||||
is not enabled by default, see <code>runtime.SetMutexProfileFraction</code> to enable it.
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
|
|
||||||
<p><strong>What other profilers can I use to profile Go programs?</strong></p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
On Linux, <a href="https://perf.wiki.kernel.org/index.php/Tutorial">perf tools</a>
|
|
||||||
can be used for profiling Go programs. Perf can profile
|
|
||||||
and unwind cgo/SWIG code and kernel, so it can be useful to get insights into
|
|
||||||
native/kernel performance bottlenecks. On macOS,
|
|
||||||
<a href="https://developer.apple.com/library/content/documentation/DeveloperTools/Conceptual/InstrumentsUserGuide/">Instruments</a>
|
|
||||||
suite can be used profile Go programs.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><strong>Can I profile my production services?</strong></p>
|
|
||||||
|
|
||||||
<p>Yes. It is safe to profile programs in production, but enabling
|
|
||||||
some profiles (e.g. the CPU profile) adds cost. You should expect to
|
|
||||||
see performance downgrade. The performance penalty can be estimated
|
|
||||||
by measuring the overhead of the profiler before turning it on in
|
|
||||||
production.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
You may want to periodically profile your production services.
|
|
||||||
Especially in a system with many replicas of a single process, selecting
|
|
||||||
a random replica periodically is a safe option.
|
|
||||||
Select a production process, profile it for
|
|
||||||
X seconds for every Y seconds and save the results for visualization and
|
|
||||||
analysis; then repeat periodically. Results may be manually and/or automatically
|
|
||||||
reviewed to find problems.
|
|
||||||
Collection of profiles can interfere with each other,
|
|
||||||
so it is recommended to collect only a single profile at a time.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
<strong>What are the best ways to visualize the profiling data?</strong>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
The Go tools provide text, graph, and <a href="http://valgrind.org/docs/manual/cl-manual.html">callgrind</a>
|
|
||||||
visualization of the profile data using
|
|
||||||
<code><a href="https://github.com/google/pprof/blob/master/doc/README.md">go tool pprof</a></code>.
|
|
||||||
Read <a href="https://blog.golang.org/profiling-go-programs">Profiling Go programs</a>
|
|
||||||
to see them in action.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
<img width="800" src="https://storage.googleapis.com/golangorg-assets/pprof-text.png">
|
|
||||||
<br>
|
|
||||||
<small>Listing of the most expensive calls as text.</small>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
<img width="800" src="https://storage.googleapis.com/golangorg-assets/pprof-dot.png">
|
|
||||||
<br>
|
|
||||||
<small>Visualization of the most expensive calls as a graph.</small>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>Weblist view displays the expensive parts of the source line by line in
|
|
||||||
an HTML page. In the following example, 530ms is spent in the
|
|
||||||
<code>runtime.concatstrings</code> and cost of each line is presented
|
|
||||||
in the listing.</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
<img width="800" src="https://storage.googleapis.com/golangorg-assets/pprof-weblist.png">
|
|
||||||
<br>
|
|
||||||
<small>Visualization of the most expensive calls as weblist.</small>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Another way to visualize profile data is a <a href="http://www.brendangregg.com/flamegraphs.html">flame graph</a>.
|
|
||||||
Flame graphs allow you to move in a specific ancestry path, so you can zoom
|
|
||||||
in/out of specific sections of code.
|
|
||||||
The <a href="https://github.com/google/pprof">upstream pprof</a>
|
|
||||||
has support for flame graphs.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
<img width="800" src="https://storage.googleapis.com/golangorg-assets/flame.png">
|
|
||||||
<br>
|
|
||||||
<small>Flame graphs offers visualization to spot the most expensive code-paths.</small>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><strong>Am I restricted to the built-in profiles?</strong></p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Additionally to what is provided by the runtime, Go users can create
|
|
||||||
their custom profiles via <a href="/pkg/runtime/pprof/#Profile">pprof.Profile</a>
|
|
||||||
and use the existing tools to examine them.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><strong>Can I serve the profiler handlers (/debug/pprof/...) on a different path and port?</strong></p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Yes. The <code>net/http/pprof</code> package registers its handlers to the default
|
|
||||||
mux by default, but you can also register them yourself by using the handlers
|
|
||||||
exported from the package.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
For example, the following example will serve the pprof.Profile
|
|
||||||
handler on :7777 at /custom_debug_path/profile:
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
<pre>
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"log"
|
|
||||||
"net/http"
|
|
||||||
"net/http/pprof"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
mux := http.NewServeMux()
|
|
||||||
mux.HandleFunc("/custom_debug_path/profile", pprof.Profile)
|
|
||||||
log.Fatal(http.ListenAndServe(":7777", mux))
|
|
||||||
}
|
|
||||||
</pre>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h2 id="tracing">Tracing</h2>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Tracing is a way to instrument code to analyze latency throughout the
|
|
||||||
lifecycle of a chain of calls. Go provides
|
|
||||||
<a href="https://godoc.org/golang.org/x/net/trace">golang.org/x/net/trace</a>
|
|
||||||
package as a minimal tracing backend per Go node and provides a minimal
|
|
||||||
instrumentation library with a simple dashboard. Go also provides
|
|
||||||
an execution tracer to trace the runtime events within an interval.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>Tracing enables us to:</p>
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li>Instrument and analyze application latency in a Go process.</li>
|
|
||||||
<li>Measure the cost of specific calls in a long chain of calls.</li>
|
|
||||||
<li>Figure out the utilization and performance improvements.
|
|
||||||
Bottlenecks are not always obvious without tracing data.</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
In monolithic systems, it's relatively easy to collect diagnostic data
|
|
||||||
from the building blocks of a program. All modules live within one
|
|
||||||
process and share common resources to report logs, errors, and other
|
|
||||||
diagnostic information. Once your system grows beyond a single process and
|
|
||||||
starts to become distributed, it becomes harder to follow a call starting
|
|
||||||
from the front-end web server to all of its back-ends until a response is
|
|
||||||
returned back to the user. This is where distributed tracing plays a big
|
|
||||||
role to instrument and analyze your production systems.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Distributed tracing is a way to instrument code to analyze latency throughout
|
|
||||||
the lifecycle of a user request. When a system is distributed and when
|
|
||||||
conventional profiling and debugging tools don’t scale, you might want
|
|
||||||
to use distributed tracing tools to analyze the performance of your user
|
|
||||||
requests and RPCs.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>Distributed tracing enables us to:</p>
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li>Instrument and profile application latency in a large system.</li>
|
|
||||||
<li>Track all RPCs within the lifecycle of a user request and see integration issues
|
|
||||||
that are only visible in production.</li>
|
|
||||||
<li>Figure out performance improvements that can be applied to our systems.
|
|
||||||
Many bottlenecks are not obvious before the collection of tracing data.</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<p>The Go ecosystem provides various distributed tracing libraries per tracing system
|
|
||||||
and backend-agnostic ones.</p>
|
|
||||||
|
|
||||||
|
|
||||||
<p><strong>Is there a way to automatically intercept each function call and create traces?</strong></p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Go doesn’t provide a way to automatically intercept every function call and create
|
|
||||||
trace spans. You need to manually instrument your code to create, end, and annotate spans.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><strong>How should I propagate trace headers in Go libraries?</strong></p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
You can propagate trace identifiers and tags in the
|
|
||||||
<a href="/pkg/context#Context"><code>context.Context</code></a>.
|
|
||||||
There is no canonical trace key or common representation of trace headers
|
|
||||||
in the industry yet. Each tracing provider is responsible for providing propagation
|
|
||||||
utilities in their Go libraries.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
<strong>What other low-level events from the standard library or
|
|
||||||
runtime can be included in a trace?</strong>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
The standard library and runtime are trying to expose several additional APIs
|
|
||||||
to notify on low level internal events. For example,
|
|
||||||
<a href="/pkg/net/http/httptrace#ClientTrace"><code>httptrace.ClientTrace</code></a>
|
|
||||||
provides APIs to follow low-level events in the life cycle of an outgoing request.
|
|
||||||
There is an ongoing effort to retrieve low-level runtime events from
|
|
||||||
the runtime execution tracer and allow users to define and record their user events.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h2 id="debugging">Debugging</h2>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Debugging is the process of identifying why a program misbehaves.
|
|
||||||
Debuggers allow us to understand a program’s execution flow and current state.
|
|
||||||
There are several styles of debugging; this section will only focus on attaching
|
|
||||||
a debugger to a program and core dump debugging.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>Go users mostly use the following debuggers:</p>
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
<a href="https://github.com/derekparker/delve">Delve</a>:
|
|
||||||
Delve is a debugger for the Go programming language. It has
|
|
||||||
support for Go’s runtime concepts and built-in types. Delve is
|
|
||||||
trying to be a fully featured reliable debugger for Go programs.
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="https://golang.org/doc/gdb">GDB</a>:
|
|
||||||
Go provides GDB support via the standard Go compiler and Gccgo.
|
|
||||||
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. Even though
|
|
||||||
GDB can be used to debug Go programs, it is not ideal and may
|
|
||||||
create confusion.
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<p><strong>How well do debuggers work with Go programs?</strong></p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
The <code>gc</code> compiler performs optimizations such as
|
|
||||||
function inlining and variable registerization. These optimizations
|
|
||||||
sometimes make debugging with debuggers harder. There is an ongoing
|
|
||||||
effort to improve the quality of the DWARF information generated for
|
|
||||||
optimized binaries. Until those improvements are available, we recommend
|
|
||||||
disabling optimizations when building the code being debugged. The following
|
|
||||||
command builds a package with no compiler optimizations:
|
|
||||||
|
|
||||||
<p>
|
|
||||||
<pre>
|
|
||||||
$ go build -gcflags=all="-N -l"
|
|
||||||
</pre>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
As part of the improvement effort, Go 1.10 introduced a new compiler
|
|
||||||
flag <code>-dwarflocationlists</code>. The flag causes the compiler to
|
|
||||||
add location lists that helps debuggers work with optimized binaries.
|
|
||||||
The following command builds a package with optimizations but with
|
|
||||||
the DWARF location lists:
|
|
||||||
|
|
||||||
<p>
|
|
||||||
<pre>
|
|
||||||
$ go build -gcflags="-dwarflocationlists=true"
|
|
||||||
</pre>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><strong>What’s the recommended debugger user interface?</strong></p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Even though both delve and gdb provides CLIs, most editor integrations
|
|
||||||
and IDEs provides debugging-specific user interfaces.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><strong>Is it possible to do postmortem debugging with Go programs?</strong></p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
A core dump file is a file that contains the memory dump of a running
|
|
||||||
process and its process status. It is primarily used for post-mortem
|
|
||||||
debugging of a program and to understand its state
|
|
||||||
while it is still running. These two cases make debugging of core
|
|
||||||
dumps a good diagnostic aid to postmortem and analyze production
|
|
||||||
services. It is possible to obtain core files from Go programs and
|
|
||||||
use delve or gdb to debug, see the
|
|
||||||
<a href="https://golang.org/wiki/CoreDumpDebugging">core dump debugging</a>
|
|
||||||
page for a step-by-step guide.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h2 id="runtime">Runtime statistics and events</h2>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
The runtime provides stats and reporting of internal events for
|
|
||||||
users to diagnose performance and utilization problems at the
|
|
||||||
runtime level.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Users can monitor these stats to better understand the overall
|
|
||||||
health and performance of Go programs.
|
|
||||||
Some frequently monitored stats and states:
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li><code><a href="/pkg/runtime/#ReadMemStats">runtime.ReadMemStats</a></code>
|
|
||||||
reports the metrics related to heap
|
|
||||||
allocation and garbage collection. Memory stats are useful for
|
|
||||||
monitoring how much memory resources a process is consuming,
|
|
||||||
whether the process can utilize memory well, and to catch
|
|
||||||
memory leaks.</li>
|
|
||||||
<li><code><a href="/pkg/runtime/debug/#ReadGCStats">debug.ReadGCStats</a></code>
|
|
||||||
reads statistics about garbage collection.
|
|
||||||
It is useful to see how much of the resources are spent on GC pauses.
|
|
||||||
It also reports a timeline of garbage collector pauses and pause time percentiles.</li>
|
|
||||||
<li><code><a href="/pkg/runtime/debug/#Stack">debug.Stack</a></code>
|
|
||||||
returns the current stack trace. Stack trace
|
|
||||||
is useful to see how many goroutines are currently running,
|
|
||||||
what they are doing, and whether they are blocked or not.</li>
|
|
||||||
<li><code><a href="/pkg/runtime/debug/#WriteHeapDump">debug.WriteHeapDump</a></code>
|
|
||||||
suspends the execution of all goroutines
|
|
||||||
and allows you to dump the heap to a file. A heap dump is a
|
|
||||||
snapshot of a Go process' memory at a given time. It contains all
|
|
||||||
allocated objects as well as goroutines, finalizers, and more.</li>
|
|
||||||
<li><code><a href="/pkg/runtime#NumGoroutine">runtime.NumGoroutine</a></code>
|
|
||||||
returns the number of current goroutines.
|
|
||||||
The value can be monitored to see whether enough goroutines are
|
|
||||||
utilized, or to detect goroutine leaks.</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<h3 id="execution-tracer">Execution tracer</h3>
|
|
||||||
|
|
||||||
<p>Go comes with a runtime execution tracer to capture a wide range
|
|
||||||
of runtime events. Scheduling, syscall, garbage collections,
|
|
||||||
heap size, and other events are collected by runtime and available
|
|
||||||
for visualization by the go tool trace. Execution tracer is a tool
|
|
||||||
to detect latency and utilization problems. You can examine how well
|
|
||||||
the CPU is utilized, and when networking or syscalls are a cause of
|
|
||||||
preemption for the goroutines.</p>
|
|
||||||
|
|
||||||
<p>Tracer is useful to:</p>
|
|
||||||
<ul>
|
|
||||||
<li>Understand how your goroutines execute.</li>
|
|
||||||
<li>Understand some of the core runtime events such as GC runs.</li>
|
|
||||||
<li>Identify poorly parallelized execution.</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<p>However, it is not great for identifying hot spots such as
|
|
||||||
analyzing the cause of excessive memory or CPU usage.
|
|
||||||
Use profiling tools instead first to address them.</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
<img width="800" src="https://storage.googleapis.com/golangorg-assets/tracer-lock.png">
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>Above, the go tool trace visualization shows the execution started
|
|
||||||
fine, and then it became serialized. It suggests that there might
|
|
||||||
be lock contention for a shared resource that creates a bottleneck.</p>
|
|
||||||
|
|
||||||
<p>See <a href="https://golang.org/cmd/trace/"><code>go</code> <code>tool</code> <code>trace</code></a>
|
|
||||||
to collect and analyze runtime traces.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h3 id="godebug">GODEBUG</h3>
|
|
||||||
|
|
||||||
<p>Runtime also emits events and information if
|
|
||||||
<a href="https://golang.org/pkg/runtime/#hdr-Environment_Variables">GODEBUG</a>
|
|
||||||
environmental variable is set accordingly.</p>
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li>GODEBUG=gctrace=1 prints garbage collector events at
|
|
||||||
each collection, summarizing the amount of memory collected
|
|
||||||
and the length of the pause.</li>
|
|
||||||
<li>GODEBUG=inittrace=1 prints a summary of execution time and memory allocation
|
|
||||||
information for completed package initialization work.</li>
|
|
||||||
<li>GODEBUG=schedtrace=X prints scheduling events every X milliseconds.</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<p>The GODEBUG environmental variable can be used to disable use of
|
|
||||||
instruction set extensions in the standard library and runtime.</p>
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li>GODEBUG=cpu.all=off disables the use of all optional
|
|
||||||
instruction set extensions.</li>
|
|
||||||
<li>GODEBUG=cpu.<em>extension</em>=off disables use of instructions from the
|
|
||||||
specified instruction set extension.<br>
|
|
||||||
<em>extension</em> is the lower case name for the instruction set extension
|
|
||||||
such as <em>sse41</em> or <em>avx</em>.</li>
|
|
||||||
</ul>
|
|
|
@ -1,33 +0,0 @@
|
||||||
<!--{
|
|
||||||
"Title": "Editor plugins and IDEs",
|
|
||||||
"Template": true
|
|
||||||
}-->
|
|
||||||
|
|
||||||
<h2 id="introduction">Introduction</h2>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
This document lists commonly used editor plugins and IDEs from the Go ecosystem
|
|
||||||
that make Go development more productive and seamless.
|
|
||||||
A comprehensive list of editor support and IDEs for Go development is available at
|
|
||||||
<a href="https://golang.org/wiki/IDEsAndTextEditorPlugins">the wiki</a>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h2 id="options">Options</h2>
|
|
||||||
<p>
|
|
||||||
The Go ecosystem provides a variety of editor plugins and IDEs to enhance your day-to-day
|
|
||||||
editing, navigation, testing, and debugging experience.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li><a href="https://marketplace.visualstudio.com/items?itemName=golang.go">Visual Studio Code</a>:
|
|
||||||
Go extension provides support for the Go programming language</li>
|
|
||||||
<li><a href="https://www.jetbrains.com/go">GoLand</a>: GoLand is distributed either as a standalone IDE
|
|
||||||
or as a plugin for IntelliJ IDEA Ultimate</li>
|
|
||||||
<li><a href="https://github.com/fatih/vim-go">vim</a>: vim-go plugin provides Go programming language support</li>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Note that these are only a few top solutions; a more comprehensive
|
|
||||||
community-maintained list of
|
|
||||||
<a href="https://github.com/golang/go/wiki/IDEsAndTextEditorPlugins">IDEs and text editor plugins</a>
|
|
||||||
is available at the Wiki.
|
|
||||||
</p>
|
|
|
@ -1,112 +0,0 @@
|
||||||
<!--{
|
|
||||||
"Title": "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://go.googlesource.com/gofrontend/+/master/HACKING">the
|
|
||||||
file HACKING</a> in the gofrontend repository.
|
|
||||||
</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="https://gcc.gnu.org/contribute.html">GCC
|
|
||||||
contribution rules</a>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h2>Code</h2>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
The master sources for the gccgo frontend may be found at
|
|
||||||
<a href="https://go.googlesource.com/gofrontend">https://go.googlesource.com/gofrontend</a>.
|
|
||||||
They are mirrored
|
|
||||||
at <a href="https://github.com/golang/gofrontend">https://github.com/golang/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="//go.googlesource.com/go">the main Go repository</a>
|
|
||||||
is mirrored to the <code>gcc/testsuite/go.test/test</code> directory
|
|
||||||
in the GCC repository.
|
|
||||||
</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 and GCC coding standards for C++.
|
|
||||||
In writing code for the frontend, follow the formatting of the
|
|
||||||
surrounding code.
|
|
||||||
Almost all GCC-specific code is not in the frontend proper and is
|
|
||||||
instead in the GCC sources in the <code>gcc/go</code> directory.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
The run-time library for gccgo is mostly the same as the library
|
|
||||||
in <a href="//go.googlesource.com/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.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h2>Testing</h2>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
All patches must be tested. 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>.
|
|
||||||
</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
|
|
||||||
the <code>gcc/testsuite/go.go-torture</code>
|
|
||||||
or <code>gcc/testsuite/go.dg</code> directories in the GCC 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.
|
|
||||||
</p>
|
|
|
@ -1,533 +0,0 @@
|
||||||
<!--{
|
|
||||||
"Title": "Setting up and using gccgo",
|
|
||||||
"Path": "/doc/install/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
|
|
||||||
the <a href="https://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).
|
|
||||||
</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
|
|
||||||
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="https://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>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
The GCC 5 releases include a complete implementation of the Go 1.4
|
|
||||||
user libraries. The Go 1.4 runtime is not fully merged, but that
|
|
||||||
should not be visible to Go programs.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
The GCC 6 releases include a complete implementation of the Go 1.6.1
|
|
||||||
user libraries. The Go 1.6 runtime is not fully merged, but that
|
|
||||||
should not be visible to Go programs.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
The GCC 7 releases include a complete implementation of the Go 1.8.1
|
|
||||||
user libraries. As with earlier releases, the Go 1.8 runtime is not
|
|
||||||
fully merged, but that should not be visible to Go programs.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
The GCC 8 releases include a complete implementation of the Go 1.10.1
|
|
||||||
release. The Go 1.10 runtime has now been fully merged into the GCC
|
|
||||||
development sources, and concurrent garbage collection is fully
|
|
||||||
supported.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
The GCC 9 releases include a complete implementation of the Go 1.12.2
|
|
||||||
release.
|
|
||||||
</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 Git. The GCC web site has
|
|
||||||
<a href="https://gcc.gnu.org/git.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 the
|
|
||||||
<code>devel/gccgo</code> branch of the main GCC code repository:
|
|
||||||
<code>git://gcc.gnu.org/git/gcc.git</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
|
|
||||||
gccgo</a>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
|
|
||||||
<h2 id="Building">Building</h2>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Building gccgo is just like building GCC
|
|
||||||
with one or two additional options. See
|
|
||||||
the <a href="https://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
|
|
||||||
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>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h3 id="Gold">Gold</h3>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
On x86 GNU/Linux systems the gccgo 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
|
|
||||||
this (you can replace <code>/opt/gold</code> with any directory to
|
|
||||||
which you have write access):
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
git clone git://sourceware.org/git/binutils-gdb.git
|
|
||||||
mkdir binutils-objdir
|
|
||||||
cd binutils-objdir
|
|
||||||
../binutils-gdb/configure --enable-gold=default --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="https://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):
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
git clone --branch devel/gccgo git://gcc.gnu.org/git/gcc.git gccgo
|
|
||||||
mkdir objdir
|
|
||||||
cd objdir
|
|
||||||
../gccgo/configure --prefix=/opt/gccgo --enable-languages=c,c++,go --with-ld=/opt/gold/bin/ld
|
|
||||||
make
|
|
||||||
make install
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<h2 id="Using_gccgo">Using gccgo</h2>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
The gccgo compiler works like other gcc frontends. As of GCC 5 the gccgo
|
|
||||||
installation also includes a version of the <code>go</code> command,
|
|
||||||
which may be used to build Go programs as described at
|
|
||||||
<a href="https://golang.org/cmd/go">https://golang.org/cmd/go</a>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
To compile a file without using the <code>go</code> command:
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
gccgo -c file.go
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
That produces <code>file.o</code>. To link files together to form an
|
|
||||||
executable:
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
gccgo -o file file.o
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<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>
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
LD_LIBRARY_PATH=${prefix}/lib/gcc/MACHINE/VERSION
|
|
||||||
[or]
|
|
||||||
LD_LIBRARY_PATH=${prefix}/lib64/gcc/MACHINE/VERSION
|
|
||||||
export LD_LIBRARY_PATH
|
|
||||||
</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 (replace lib with
|
|
||||||
lib64 if appropriate for your system):
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
go build -gccgoflags -Wl,-R,${prefix}/lib/gcc/MACHINE/VERSION
|
|
||||||
[or]
|
|
||||||
gccgo -o file file.o -Wl,-R,${prefix}/lib/gcc/MACHINE/VERSION
|
|
||||||
</pre>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
<p>
|
|
||||||
Use the <code>-static-libgo</code> option to link statically against
|
|
||||||
the compiled packages.
|
|
||||||
</p>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<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>
|
|
||||||
|
|
||||||
<h2 id="Options">Options</h2>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
The gccgo compiler supports all GCC options
|
|
||||||
that are language independent, notably the <code>-O</code>
|
|
||||||
and <code>-g</code> options.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
The <code>-fgo-pkgpath=PKGPATH</code> option may be used to set a
|
|
||||||
unique prefix for the package being compiled.
|
|
||||||
This option is automatically used by the go command, but you may want
|
|
||||||
to use it if you invoke gccgo directly.
|
|
||||||
This option is intended for 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>PKGPATH</code> may be any string; a good choice for the
|
|
||||||
string is the path used to import the package.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<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.
|
|
||||||
These options are not needed if you build with the go command.
|
|
||||||
</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.
|
|
||||||
If you build with gccgo directly, rather than with the go command,
|
|
||||||
then when you import a package, you must tell gccgo how to find the
|
|
||||||
file.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
When you import the package <var>FILE</var> with gccgo,
|
|
||||||
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>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
|
|
||||||
may pass the <code>-I</code> or <code>-L</code> option to
|
|
||||||
gccgo. 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 (2015-06-15) record
|
|
||||||
the file name of imported packages in the object file. You must
|
|
||||||
arrange for the imported data to be linked into the program.
|
|
||||||
Again, this is not necessary when building with the go command.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
gccgo -c mypackage.go # Exports mypackage
|
|
||||||
gccgo -c main.go # Imports mypackage
|
|
||||||
gccgo -o main main.o mypackage.o # Explicitly links with mypackage.o
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<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,
|
|
||||||
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>
|
|
||||||
|
|
||||||
<h2 id="C_Interoperability">C Interoperability</h2>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
When using gccgo 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>int32</code> in Go is
|
|
||||||
an <code>int32_t</code> in C, an <code>int64</code> is
|
|
||||||
an <code>int64_t</code>, etc.
|
|
||||||
The Go type <code>int</code> is an integer that is the same size as a
|
|
||||||
pointer, and as such corresponds to the C type <code>intptr_t</code>.
|
|
||||||
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 {
|
|
||||||
const unsigned char *__data;
|
|
||||||
intptr_t __length;
|
|
||||||
};
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
You can't pass arrays between C and Go. However, a pointer to an
|
|
||||||
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 {
|
|
||||||
void *__values;
|
|
||||||
intptr_t __count;
|
|
||||||
intptr_t __capacity;
|
|
||||||
};
|
|
||||||
</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>
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
func GoFunction(int) (int, float64)
|
|
||||||
struct { int i; float64 f; } CFunction(int, void*)
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Go <code>interface</code>, <code>channel</code>, and <code>map</code>
|
|
||||||
types have no corresponding C type (<code>interface</code> is a
|
|
||||||
two-element struct and <code>channel</code> and <code>map</code> are
|
|
||||||
pointers to structs in C, but the structs are deliberately undocumented). C
|
|
||||||
<code>enum</code> types correspond to some integer type, but precisely
|
|
||||||
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
|
|
||||||
garbage collection. The exact guidelines in this area are undetermined,
|
|
||||||
but it is likely that it will be permitted to pass a pointer to allocated
|
|
||||||
memory from C to Go. The responsibility of eventually freeing the pointer
|
|
||||||
will remain with C side, and of course if the C side frees the pointer
|
|
||||||
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
|
|
||||||
<code>open</code> can be declared in Go:
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
//extern open
|
|
||||||
func c_open(name *byte, mode int, perm int) int
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
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>
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
var name = [4]byte{'f', 'o', 'o', 0};
|
|
||||||
i := c_open(&name[0], syscall.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>.
|
|
||||||
To call the function from C you must set the name using
|
|
||||||
a GCC extension.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
extern int go_function(int) __asm__ ("myprefix.mypackage.Function");
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<h3 id="Automatic_generation_of_Go_declarations_from_C_source_code">
|
|
||||||
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>
|
|
||||||
|
|
||||||
<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>
|
|
||||||
|
|
||||||
<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>
|
|
Двоичные данные
doc/go-logo-black.png
До Ширина: | Высота: | Размер: 8.6 KiB |
Двоичные данные
doc/go-logo-blue.png
До Ширина: | Высота: | Размер: 9.1 KiB |
Двоичные данные
doc/go-logo-white.png
До Ширина: | Высота: | Размер: 21 KiB |
1099
doc/go1.1.html
1448
doc/go1.10.html
934
doc/go1.11.html
|
@ -1,934 +0,0 @@
|
||||||
<!--{
|
|
||||||
"Title": "Go 1.11 Release Notes",
|
|
||||||
"Path": "/doc/go1.11",
|
|
||||||
"Template": true
|
|
||||||
}-->
|
|
||||||
|
|
||||||
<!--
|
|
||||||
NOTE: In this document and others in this directory, the convention is to
|
|
||||||
set fixed-width phrases with non-fixed-width spaces, as in
|
|
||||||
<code>hello</code> <code>world</code>.
|
|
||||||
Do not send CLs removing the interior tags from such phrases.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<style>
|
|
||||||
main ul li { margin: 0.5em 0; }
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<h2 id="introduction">Introduction to Go 1.11</h2>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
The latest Go release, version 1.11, arrives six months after <a href="go1.10">Go 1.10</a>.
|
|
||||||
Most of its changes are in the implementation of the toolchain, runtime, and libraries.
|
|
||||||
As always, the release maintains the Go 1 <a href="/doc/go1compat.html">promise of compatibility</a>.
|
|
||||||
We expect almost all Go programs to continue to compile and run as before.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h2 id="language">Changes to the language</h2>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
There are no changes to the language specification.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h2 id="ports">Ports</h2>
|
|
||||||
|
|
||||||
<p> <!-- CL 94255, CL 115038, etc -->
|
|
||||||
As <a href="go1.10#ports">announced in the Go 1.10 release notes</a>, Go 1.11 now requires
|
|
||||||
OpenBSD 6.2 or later, macOS 10.10 Yosemite or later, or Windows 7 or later;
|
|
||||||
support for previous versions of these operating systems has been removed.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p> <!-- CL 121657 -->
|
|
||||||
Go 1.11 supports the upcoming OpenBSD 6.4 release. Due to changes in
|
|
||||||
the OpenBSD kernel, older versions of Go will not work on OpenBSD 6.4.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
There are <a href="https://golang.org/issue/25206">known issues</a> with NetBSD on i386 hardware.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 107935 -->
|
|
||||||
The race detector is now supported on <code>linux/ppc64le</code>
|
|
||||||
and, to a lesser extent, on <code>netbsd/amd64</code>. The NetBSD race detector support
|
|
||||||
has <a href="https://golang.org/issue/26403">known issues</a>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 109255 -->
|
|
||||||
The memory sanitizer (<code>-msan</code>) is now supported on <code>linux/arm64</code>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 93875 -->
|
|
||||||
The build modes <code>c-shared</code> and <code>c-archive</code> are now supported on
|
|
||||||
<code>freebsd/amd64</code>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p id="mips"><!-- CL 108475 -->
|
|
||||||
On 64-bit MIPS systems, the new environment variable settings
|
|
||||||
<code>GOMIPS64=hardfloat</code> (the default) and
|
|
||||||
<code>GOMIPS64=softfloat</code> select whether to use
|
|
||||||
hardware instructions or software emulation for floating-point computations.
|
|
||||||
For 32-bit systems, the environment variable is still <code>GOMIPS</code>,
|
|
||||||
as <a href="go1.10#mips">added in Go 1.10</a>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 107475 -->
|
|
||||||
On soft-float ARM systems (<code>GOARM=5</code>), Go now uses a more
|
|
||||||
efficient software floating point interface. This is transparent to
|
|
||||||
Go code, but ARM assembly that uses floating-point instructions not
|
|
||||||
guarded on GOARM will break and must be ported to
|
|
||||||
the <a href="https://golang.org/cl/107475">new interface</a>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 94076 -->
|
|
||||||
Go 1.11 on ARMv7 no longer requires a Linux kernel configured
|
|
||||||
with <code>KUSER_HELPERS</code>. This setting is enabled in default
|
|
||||||
kernel configurations, but is sometimes disabled in stripped-down
|
|
||||||
configurations.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h3 id="wasm">WebAssembly</h3>
|
|
||||||
<p>
|
|
||||||
Go 1.11 adds an experimental port to <a href="https://webassembly.org">WebAssembly</a>
|
|
||||||
(<code>js/wasm</code>).
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
Go programs currently compile to one WebAssembly module that
|
|
||||||
includes the Go runtime for goroutine scheduling, garbage
|
|
||||||
collection, maps, etc.
|
|
||||||
As a result, the resulting size is at minimum around
|
|
||||||
2 MB, or 500 KB compressed. Go programs can call into JavaScript
|
|
||||||
using the new experimental
|
|
||||||
<a href="/pkg/syscall/js/"><code>syscall/js</code></a> package.
|
|
||||||
Binary size and interop with other languages has not yet been a
|
|
||||||
priority but may be addressed in future releases.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
As a result of the addition of the new <code>GOOS</code> value
|
|
||||||
"<code>js</code>" and <code>GOARCH</code> value "<code>wasm</code>",
|
|
||||||
Go files named <code>*_js.go</code> or <code>*_wasm.go</code> will
|
|
||||||
now be <a href="/pkg/go/build/#hdr-Build_Constraints">ignored by Go
|
|
||||||
tools</a> except when those GOOS/GOARCH values are being used.
|
|
||||||
If you have existing filenames matching those patterns, you will need to rename them.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
More information can be found on the
|
|
||||||
<a href="https://golang.org/wiki/WebAssembly">WebAssembly wiki page</a>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h3 id="riscv">RISC-V GOARCH values reserved</h3>
|
|
||||||
<p><!-- CL 106256 -->
|
|
||||||
The main Go compiler does not yet support the RISC-V architecture <!-- is gonna change everything -->
|
|
||||||
but we've reserved the <code>GOARCH</code> values
|
|
||||||
"<code>riscv</code>" and "<code>riscv64</code>", as used by Gccgo,
|
|
||||||
which does support RISC-V. This means that Go files
|
|
||||||
named <code>*_riscv.go</code> will now also
|
|
||||||
be <a href="/pkg/go/build/#hdr-Build_Constraints">ignored by Go
|
|
||||||
tools</a> except when those GOOS/GOARCH values are being used.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h2 id="tools">Tools</h2>
|
|
||||||
|
|
||||||
<h3 id="modules">Modules, package versioning, and dependency management</h3>
|
|
||||||
<p>
|
|
||||||
Go 1.11 adds preliminary support for a <a href="/cmd/go/#hdr-Modules__module_versions__and_more">new concept called “modules,”</a>
|
|
||||||
an alternative to GOPATH with integrated support for versioning and
|
|
||||||
package distribution.
|
|
||||||
Using modules, developers are no longer confined to working inside GOPATH,
|
|
||||||
version dependency information is explicit yet lightweight,
|
|
||||||
and builds are more reliable and reproducible.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Module support is considered experimental.
|
|
||||||
Details are likely to change in response to feedback from Go 1.11 users,
|
|
||||||
and we have more tools planned.
|
|
||||||
Although the details of module support may change, projects that convert
|
|
||||||
to modules using Go 1.11 will continue to work with Go 1.12 and later.
|
|
||||||
If you encounter bugs using modules,
|
|
||||||
please <a href="https://golang.org/issue/new">file issues</a>
|
|
||||||
so we can fix them. For more information, see the
|
|
||||||
<a href="/cmd/go#hdr-Modules__module_versions__and_more"><code>go</code> command documentation</a>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h3 id="importpath">Import path restriction</h3>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Because Go module support assigns special meaning to the
|
|
||||||
<code>@</code> symbol in command line operations,
|
|
||||||
the <code>go</code> command now disallows the use of
|
|
||||||
import paths containing <code>@</code> symbols.
|
|
||||||
Such import paths were never allowed by <code>go</code> <code>get</code>,
|
|
||||||
so this restriction can only affect users building
|
|
||||||
custom GOPATH trees by other means.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h3 id="gopackages">Package loading</h3>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
The new package
|
|
||||||
<a href="https://godoc.org/golang.org/x/tools/go/packages"><code>golang.org/x/tools/go/packages</code></a>
|
|
||||||
provides a simple API for locating and loading packages of Go source code.
|
|
||||||
Although not yet part of the standard library, for many tasks it
|
|
||||||
effectively replaces the <a href="/pkg/go/build"><code>go/build</code></a>
|
|
||||||
package, whose API is unable to fully support modules.
|
|
||||||
Because it runs an external query command such as
|
|
||||||
<a href="/cmd/go/#hdr-List_packages"><code>go list</code></a>
|
|
||||||
to obtain information about Go packages, it enables the construction of
|
|
||||||
analysis tools that work equally well with alternative build systems
|
|
||||||
such as <a href="https://bazel.build">Bazel</a>
|
|
||||||
and <a href="https://buckbuild.com">Buck</a>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h3 id="gocache">Build cache requirement</h3>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Go 1.11 will be the last release to support setting the environment
|
|
||||||
variable <code>GOCACHE=off</code> to disable the
|
|
||||||
<a href="/cmd/go/#hdr-Build_and_test_caching">build cache</a>,
|
|
||||||
introduced in Go 1.10.
|
|
||||||
Starting in Go 1.12, the build cache will be required,
|
|
||||||
as a step toward eliminating <code>$GOPATH/pkg</code>.
|
|
||||||
The module and package loading support described above
|
|
||||||
already require that the build cache be enabled.
|
|
||||||
If you have disabled the build cache to avoid problems you encountered,
|
|
||||||
please <a href="https://golang.org/issue/new">file an issue</a> to let us know about them.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h3 id="compiler">Compiler toolchain</h3>
|
|
||||||
|
|
||||||
<p><!-- CL 109918 -->
|
|
||||||
More functions are now eligible for inlining by default, including
|
|
||||||
functions that call <code>panic</code>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 97375 -->
|
|
||||||
The compiler toolchain now supports column information
|
|
||||||
in <a href="/cmd/compile/#hdr-Compiler_Directives">line
|
|
||||||
directives</a>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 106797 -->
|
|
||||||
A new package export data format has been introduced.
|
|
||||||
This should be transparent to end users, except for speeding up
|
|
||||||
build times for large Go projects.
|
|
||||||
If it does cause problems, it can be turned off again by
|
|
||||||
passing <code>-gcflags=all=-iexport=false</code> to
|
|
||||||
the <code>go</code> tool when building a binary.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 100459 -->
|
|
||||||
The compiler now rejects unused variables declared in a type switch
|
|
||||||
guard, such as <code>x</code> in the following example:
|
|
||||||
</p>
|
|
||||||
<pre>
|
|
||||||
func f(v interface{}) {
|
|
||||||
switch x := v.(type) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</pre>
|
|
||||||
<p>
|
|
||||||
This was already rejected by both <code>gccgo</code>
|
|
||||||
and <a href="/pkg/go/types/">go/types</a>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h3 id="assembler">Assembler</h3>
|
|
||||||
|
|
||||||
<p><!-- CL 113315 -->
|
|
||||||
The assembler for <code>amd64</code> now accepts AVX512 instructions.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h3 id="debugging">Debugging</h3>
|
|
||||||
|
|
||||||
<p><!-- CL 100738, CL 93664 -->
|
|
||||||
The compiler now produces significantly more accurate debug
|
|
||||||
information for optimized binaries, including variable location
|
|
||||||
information, line numbers, and breakpoint locations.
|
|
||||||
|
|
||||||
This should make it possible to debug binaries
|
|
||||||
compiled <em>without</em> <code>-N</code> <code>-l</code>.
|
|
||||||
|
|
||||||
There are still limitations to the quality of the debug information,
|
|
||||||
some of which are fundamental, and some of which will continue to
|
|
||||||
improve with future releases.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 118276 -->
|
|
||||||
DWARF sections are now compressed by default because of the expanded
|
|
||||||
and more accurate debug information produced by the compiler.
|
|
||||||
|
|
||||||
This is transparent to most ELF tools (such as debuggers on Linux
|
|
||||||
and *BSD) and is supported by the Delve debugger on all platforms,
|
|
||||||
but has limited support in the native tools on macOS and Windows.
|
|
||||||
|
|
||||||
To disable DWARF compression,
|
|
||||||
pass <code>-ldflags=-compressdwarf=false</code> to
|
|
||||||
the <code>go</code> tool when building a binary.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 109699 -->
|
|
||||||
Go 1.11 adds experimental support for calling Go functions from
|
|
||||||
within a debugger.
|
|
||||||
|
|
||||||
This is useful, for example, to call <code>String</code> methods
|
|
||||||
when paused at a breakpoint.
|
|
||||||
|
|
||||||
This is currently only supported by Delve (version 1.1.0 and up).
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h3 id="test">Test</h3>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Since Go 1.10, the <code>go</code> <code>test</code> command runs
|
|
||||||
<code>go</code> <code>vet</code> on the package being tested,
|
|
||||||
to identify problems before running the test. Since <code>vet</code>
|
|
||||||
typechecks the code with <a href="/pkg/go/types/">go/types</a>
|
|
||||||
before running, tests that do not typecheck will now fail.
|
|
||||||
|
|
||||||
In particular, tests that contain an unused variable inside a
|
|
||||||
closure compiled with Go 1.10, because the Go compiler incorrectly
|
|
||||||
accepted them (<a href="https://golang.org/issues/3059">Issue #3059</a>),
|
|
||||||
but will now fail, since <code>go/types</code> correctly reports an
|
|
||||||
"unused variable" error in this case.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 102696 -->
|
|
||||||
The <code>-memprofile</code> flag
|
|
||||||
to <code>go</code> <code>test</code> now defaults to the
|
|
||||||
"allocs" profile, which records the total bytes allocated since the
|
|
||||||
test began (including garbage-collected bytes).
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h3 id="vet">Vet</h3>
|
|
||||||
|
|
||||||
<p><!-- CL 108555 -->
|
|
||||||
The <a href="/cmd/vet/"><code>go</code> <code>vet</code></a>
|
|
||||||
command now reports a fatal error when the package under analysis
|
|
||||||
does not typecheck. Previously, a type checking error simply caused
|
|
||||||
a warning to be printed, and <code>vet</code> to exit with status 1.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 108559 -->
|
|
||||||
Additionally, <a href="/cmd/vet"><code>go</code> <code>vet</code></a>
|
|
||||||
has become more robust when format-checking <code>printf</code> wrappers.
|
|
||||||
Vet now detects the mistake in this example:
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
func wrapper(s string, args ...interface{}) {
|
|
||||||
fmt.Printf(s, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
wrapper("%s", 42)
|
|
||||||
}
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<h3 id="trace">Trace</h3>
|
|
||||||
|
|
||||||
<p><!-- CL 63274 -->
|
|
||||||
With the new <code>runtime/trace</code>
|
|
||||||
package's <a href="/pkg/runtime/trace/#hdr-User_annotation">user
|
|
||||||
annotation API</a>, users can record application-level information
|
|
||||||
in execution traces and create groups of related goroutines.
|
|
||||||
The <code>go</code> <code>tool</code> <code>trace</code>
|
|
||||||
command visualizes this information in the trace view and the new
|
|
||||||
user task/region analysis page.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h3 id="cgo">Cgo</h3>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Since Go 1.10, cgo has translated some C pointer types to the Go
|
|
||||||
type <code>uintptr</code>. These types include
|
|
||||||
the <code>CFTypeRef</code> hierarchy in Darwin's CoreFoundation
|
|
||||||
framework and the <code>jobject</code> hierarchy in Java's JNI
|
|
||||||
interface. In Go 1.11, several improvements have been made to the code
|
|
||||||
that detects these types. Code that uses these types may need some
|
|
||||||
updating. See the <a href="go1.10.html#cgo">Go 1.10 release notes</a> for
|
|
||||||
details. <!-- CL 126275, CL 127156, CL 122217, CL 122575, CL 123177 -->
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h3 id="go_command">Go command</h3>
|
|
||||||
|
|
||||||
<p><!-- CL 126656 -->
|
|
||||||
The environment variable <code>GOFLAGS</code> may now be used
|
|
||||||
to set default flags for the <code>go</code> command.
|
|
||||||
This is useful in certain situations.
|
|
||||||
Linking can be noticeably slower on underpowered systems due to DWARF,
|
|
||||||
and users may want to set <code>-ldflags=-w</code> by default.
|
|
||||||
For modules, some users and CI systems will want vendoring always,
|
|
||||||
so they should set <code>-mod=vendor</code> by default.
|
|
||||||
For more information, see the <a href="/cmd/go/#hdr-Environment_variables"><code>go</code>
|
|
||||||
command documentation</a>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h3 id="godoc">Godoc</h3>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Go 1.11 will be the last release to support <code>godoc</code>'s command-line interface.
|
|
||||||
In future releases, <code>godoc</code> will only be a web server. Users should use
|
|
||||||
<code>go</code> <code>doc</code> for command-line help output instead.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 85396, CL 124495 -->
|
|
||||||
The <code>godoc</code> web server now shows which version of Go introduced
|
|
||||||
new API features. The initial Go version of types, funcs, and methods are shown
|
|
||||||
right-aligned. For example, see <a href="/pkg/os/#UserCacheDir"><code>UserCacheDir</code></a>, with "1.11"
|
|
||||||
on the right side. For struct fields, inline comments are added when the struct field was
|
|
||||||
added in a Go version other than when the type itself was introduced.
|
|
||||||
For a struct field example, see
|
|
||||||
<a href="/pkg/net/http/httptrace/#ClientTrace.Got1xxResponse"><code>ClientTrace.Got1xxResponse</code></a>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h3 id="gofmt">Gofmt</h3>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
One minor detail of the default formatting of Go source code has changed.
|
|
||||||
When formatting expression lists with inline comments, the comments were
|
|
||||||
aligned according to a heuristic.
|
|
||||||
However, in some cases the alignment would be split up too easily, or
|
|
||||||
introduce too much whitespace.
|
|
||||||
The heuristic has been changed to behave better for human-written code.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Note that these kinds of minor updates to gofmt are expected from time to
|
|
||||||
time.
|
|
||||||
In general, systems that need consistent formatting of Go source code should
|
|
||||||
use a specific version of the <code>gofmt</code> binary.
|
|
||||||
See the <a href="/pkg/go/format/">go/format</a> package documentation for more
|
|
||||||
information.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h3 id="run">Run</h3>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
<!-- CL 109341 -->
|
|
||||||
The <a href="/cmd/go/"><code>go</code> <code>run</code></a>
|
|
||||||
command now allows a single import path, a directory name or a
|
|
||||||
pattern matching a single package.
|
|
||||||
This allows <code>go</code> <code>run</code> <code>pkg</code> or <code>go</code> <code>run</code> <code>dir</code>, most importantly <code>go</code> <code>run</code> <code>.</code>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h2 id="runtime">Runtime</h2>
|
|
||||||
|
|
||||||
<p><!-- CL 85887 -->
|
|
||||||
The runtime now uses a sparse heap layout so there is no longer a
|
|
||||||
limit to the size of the Go heap (previously, the limit was 512GiB).
|
|
||||||
This also fixes rare "address space conflict" failures in mixed Go/C
|
|
||||||
binaries or binaries compiled with <code>-race</code>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 108679, CL 106156 -->
|
|
||||||
On macOS and iOS, the runtime now uses <code>libSystem.dylib</code> instead of
|
|
||||||
calling the kernel directly. This should make Go binaries more
|
|
||||||
compatible with future versions of macOS and iOS.
|
|
||||||
The <a href="/pkg/syscall">syscall</a> package still makes direct
|
|
||||||
system calls; fixing this is planned for a future release.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h2 id="performance">Performance</h2>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
As always, the changes are so general and varied that precise
|
|
||||||
statements about performance are difficult to make. Most programs
|
|
||||||
should run a bit faster, due to better generated code and
|
|
||||||
optimizations in the core library.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 74851 -->
|
|
||||||
There were multiple performance changes to the <code>math/big</code>
|
|
||||||
package as well as many changes across the tree specific to <code>GOARCH=arm64</code>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h3 id="performance-compiler">Compiler toolchain</h3>
|
|
||||||
|
|
||||||
<p><!-- CL 110055 -->
|
|
||||||
The compiler now optimizes map clearing operations of the form:
|
|
||||||
</p>
|
|
||||||
<pre>
|
|
||||||
for k := range m {
|
|
||||||
delete(m, k)
|
|
||||||
}
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p><!-- CL 109517 -->
|
|
||||||
The compiler now optimizes slice extension of the form
|
|
||||||
<code>append(s,</code> <code>make([]T,</code> <code>n)...)</code>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 100277, CL 105635, CL 109776 -->
|
|
||||||
The compiler now performs significantly more aggressive bounds-check
|
|
||||||
and branch elimination. Notably, it now recognizes transitive
|
|
||||||
relations, so if <code>i<j</code> and <code>j<len(s)</code>,
|
|
||||||
it can use these facts to eliminate the bounds check
|
|
||||||
for <code>s[i]</code>. It also understands simple arithmetic such
|
|
||||||
as <code>s[i-10]</code> and can recognize more inductive cases in
|
|
||||||
loops. Furthermore, the compiler now uses bounds information to more
|
|
||||||
aggressively optimize shift operations.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h2 id="library">Core library</h2>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
All of the changes to the standard library are minor.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h3 id="minor_library_changes">Minor changes to the library</h3>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
As always, there are various minor changes and updates to the library,
|
|
||||||
made with the Go 1 <a href="/doc/go1compat">promise of compatibility</a>
|
|
||||||
in mind.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<!-- CL 115095: https://golang.org/cl/115095: yes (`go test pkg` now always builds pkg even if there are no test files): cmd/go: output coverage report even if there are no test files -->
|
|
||||||
<!-- CL 110395: https://golang.org/cl/110395: cmd/go, cmd/compile: use Windows response files to avoid arg length limits -->
|
|
||||||
<!-- CL 112436: https://golang.org/cl/112436: cmd/pprof: add readline support similar to upstream -->
|
|
||||||
|
|
||||||
|
|
||||||
<dl id="crypto"><dt><a href="/pkg/crypto/">crypto</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 64451 -->
|
|
||||||
Certain crypto operations, including
|
|
||||||
<a href="/pkg/crypto/ecdsa/#Sign"><code>ecdsa.Sign</code></a>,
|
|
||||||
<a href="/pkg/crypto/rsa/#EncryptPKCS1v15"><code>rsa.EncryptPKCS1v15</code></a> and
|
|
||||||
<a href="/pkg/crypto/rsa/#GenerateKey"><code>rsa.GenerateKey</code></a>,
|
|
||||||
now randomly read an extra byte of randomness to ensure tests don't rely on internal behavior.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</dl><!-- crypto -->
|
|
||||||
|
|
||||||
<dl id="crypto/cipher"><dt><a href="/pkg/crypto/cipher/">crypto/cipher</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 48510, CL 116435 -->
|
|
||||||
The new function <a href="/pkg/crypto/cipher/#NewGCMWithTagSize"><code>NewGCMWithTagSize</code></a>
|
|
||||||
implements Galois Counter Mode with non-standard tag lengths for compatibility with existing cryptosystems.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</dl><!-- crypto/cipher -->
|
|
||||||
|
|
||||||
<dl id="crypto/rsa"><dt><a href="/pkg/crypto/rsa/">crypto/rsa</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 103876 -->
|
|
||||||
<a href="/pkg/crypto/rsa/#PublicKey"><code>PublicKey</code></a> now implements a
|
|
||||||
<a href="/pkg/crypto/rsa/#PublicKey.Size"><code>Size</code></a> method that
|
|
||||||
returns the modulus size in bytes.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</dl><!-- crypto/rsa -->
|
|
||||||
|
|
||||||
<dl id="crypto/tls"><dt><a href="/pkg/crypto/tls/">crypto/tls</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 85115 -->
|
|
||||||
<a href="/pkg/crypto/tls/#ConnectionState"><code>ConnectionState</code></a>'s new
|
|
||||||
<a href="/pkg/crypto/tls/#ConnectionState.ExportKeyingMaterial"><code>ExportKeyingMaterial</code></a>
|
|
||||||
method allows exporting keying material bound to the
|
|
||||||
connection according to RFC 5705.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</dl><!-- crypto/tls -->
|
|
||||||
|
|
||||||
<dl id="crypto/x509"><dt><a href="/pkg/crypto/x509/">crypto/x509</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 123355, CL 123695 -->
|
|
||||||
The deprecated, legacy behavior of treating the <code>CommonName</code> field as
|
|
||||||
a hostname when no Subject Alternative Names are present is now disabled when the CN is not a
|
|
||||||
valid hostname.
|
|
||||||
The <code>CommonName</code> can be completely ignored by adding the experimental value
|
|
||||||
<code>x509ignoreCN=1</code> to the <code>GODEBUG</code> environment variable.
|
|
||||||
When the CN is ignored, certificates without SANs validate under chains with name constraints
|
|
||||||
instead of returning <code>NameConstraintsWithoutSANs</code>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 113475 -->
|
|
||||||
Extended key usage restrictions are again checked only if they appear in the <code>KeyUsages</code>
|
|
||||||
field of <a href="/pkg/crypto/x509/#VerifyOptions"><code>VerifyOptions</code></a>, instead of always being checked.
|
|
||||||
This matches the behavior of Go 1.9 and earlier.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 102699 -->
|
|
||||||
The value returned by <a href="/pkg/crypto/x509/#SystemCertPool"><code>SystemCertPool</code></a>
|
|
||||||
is now cached and might not reflect system changes between invocations.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</dl><!-- crypto/x509 -->
|
|
||||||
|
|
||||||
<dl id="debug/elf"><dt><a href="/pkg/debug/elf/">debug/elf</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 112115 -->
|
|
||||||
More <a href="/pkg/debug/elf/#ELFOSABI_NONE"><code>ELFOSABI</code></a>
|
|
||||||
and <a href="/pkg/debug/elf/#EM_NONE"><code>EM</code></a>
|
|
||||||
constants have been added.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</dl><!-- debug/elf -->
|
|
||||||
|
|
||||||
<dl id="encoding/asn1"><dt><a href="/pkg/encoding/asn1/">encoding/asn1</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 110561 -->
|
|
||||||
<code>Marshal</code> and <code><a href="/pkg/encoding/asn1/#Unmarshal">Unmarshal</a></code>
|
|
||||||
now support "private" class annotations for fields.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</dl><!-- encoding/asn1 -->
|
|
||||||
|
|
||||||
<dl id="encoding/base32"><dt><a href="/pkg/encoding/base32/">encoding/base32</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 112516 -->
|
|
||||||
The decoder now consistently
|
|
||||||
returns <code>io.ErrUnexpectedEOF</code> for an incomplete
|
|
||||||
chunk. Previously it would return <code>io.EOF</code> in some
|
|
||||||
cases.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</dl><!-- encoding/base32 -->
|
|
||||||
|
|
||||||
<dl id="encoding/csv"><dt><a href="/pkg/encoding/csv/">encoding/csv</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 99696 -->
|
|
||||||
The <code>Reader</code> now rejects attempts to set
|
|
||||||
the <a href="/pkg/encoding/csv/#Reader.Comma"><code>Comma</code></a>
|
|
||||||
field to a double-quote character, as double-quote characters
|
|
||||||
already have a special meaning in CSV.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</dl><!-- encoding/csv -->
|
|
||||||
|
|
||||||
<!-- CL 100235 was reverted -->
|
|
||||||
|
|
||||||
<dl id="html/template"><dt><a href="/pkg/html/template/">html/template</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 121815 -->
|
|
||||||
The package has changed its behavior when a typed interface
|
|
||||||
value is passed to an implicit escaper function. Previously such
|
|
||||||
a value was written out as (an escaped form)
|
|
||||||
of <code><nil></code>. Now such values are ignored, just
|
|
||||||
as an untyped <code>nil</code> value is (and always has been)
|
|
||||||
ignored.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</dl><!-- html/template -->
|
|
||||||
|
|
||||||
<dl id="image/gif"><dt><a href="/pkg/image/gif/">image/gif</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 93076 -->
|
|
||||||
Non-looping animated GIFs are now supported. They are denoted by having a
|
|
||||||
<code><a href="/pkg/image/gif/#GIF.LoopCount">LoopCount</a></code> of -1.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</dl><!-- image/gif -->
|
|
||||||
|
|
||||||
<dl id="io/ioutil"><dt><a href="/pkg/io/ioutil/">io/ioutil</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 105675 -->
|
|
||||||
The <code><a href="/pkg/io/ioutil/#TempFile">TempFile</a></code>
|
|
||||||
function now supports specifying where the random characters in
|
|
||||||
the filename are placed. If the <code>prefix</code> argument
|
|
||||||
includes a "<code>*</code>", the random string replaces the
|
|
||||||
"<code>*</code>". For example, a <code>prefix</code> argument of "<code>myname.*.bat</code>" will
|
|
||||||
result in a random filename such as
|
|
||||||
"<code>myname.123456.bat</code>". If no "<code>*</code>" is
|
|
||||||
included the old behavior is retained, and the random digits are
|
|
||||||
appended to the end.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</dl><!-- io/ioutil -->
|
|
||||||
|
|
||||||
<dl id="math/big"><dt><a href="/pkg/math/big/">math/big</a></dt>
|
|
||||||
<dd>
|
|
||||||
|
|
||||||
<p><!-- CL 108996 -->
|
|
||||||
<a href="/pkg/math/big/#Int.ModInverse"><code>ModInverse</code></a> now returns nil when g and n are not relatively prime. The result was previously undefined.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</dl><!-- math/big -->
|
|
||||||
|
|
||||||
<dl id="mime/multipart"><dt><a href="/pkg/mime/multipart/">mime/multipart</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 121055 -->
|
|
||||||
The handling of form-data with missing/empty file names has been
|
|
||||||
restored to the behavior in Go 1.9: in the
|
|
||||||
<a href="/pkg/mime/multipart/#Form"><code>Form</code></a> for
|
|
||||||
the form-data part the value is available in
|
|
||||||
the <code>Value</code> field rather than the <code>File</code>
|
|
||||||
field. In Go releases 1.10 through 1.10.3 a form-data part with
|
|
||||||
a missing/empty file name and a non-empty "Content-Type" field
|
|
||||||
was stored in the <code>File</code> field. This change was a
|
|
||||||
mistake in 1.10 and has been reverted to the 1.9 behavior.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</dl><!-- mime/multipart -->
|
|
||||||
|
|
||||||
<dl id="mime/quotedprintable"><dt><a href="/pkg/mime/quotedprintable/">mime/quotedprintable</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 121095 -->
|
|
||||||
To support invalid input found in the wild, the package now
|
|
||||||
permits non-ASCII bytes but does not validate their encoding.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</dl><!-- mime/quotedprintable -->
|
|
||||||
|
|
||||||
<dl id="net"><dt><a href="/pkg/net/">net</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 72810 -->
|
|
||||||
The new <a href="/pkg/net/#ListenConfig"><code>ListenConfig</code></a> type and the new
|
|
||||||
<a href="/pkg/net/#Dialer.Control"><code>Dialer.Control</code></a> field permit
|
|
||||||
setting socket options before accepting and creating connections, respectively.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 76391 -->
|
|
||||||
The <a href="/pkg/syscall/#RawConn"><code>syscall.RawConn</code></a> <code>Read</code>
|
|
||||||
and <code>Write</code> methods now work correctly on Windows.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 107715 -->
|
|
||||||
The <code>net</code> package now automatically uses the
|
|
||||||
<a href="http://man7.org/linux/man-pages/man2/splice.2.html"><code>splice</code> system call</a>
|
|
||||||
on Linux when copying data between TCP connections in
|
|
||||||
<a href="/pkg/net/#TCPConn.ReadFrom"><code>TCPConn.ReadFrom</code></a>, as called by
|
|
||||||
<a href="/pkg/io/#Copy"><code>io.Copy</code></a>. The result is faster, more efficient TCP proxying.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 108297 -->
|
|
||||||
The <a href="/pkg/net/#TCPConn.File"><code>TCPConn.File</code></a>,
|
|
||||||
<a href="/pkg/net/#UDPConn.File"><code>UDPConn.File</code></a>,
|
|
||||||
<a href="/pkg/net/#UnixCOnn.File"><code>UnixConn.File</code></a>,
|
|
||||||
and <a href="/pkg/net/#IPConn.File"><code>IPConn.File</code></a>
|
|
||||||
methods no longer put the returned <code>*os.File</code> into
|
|
||||||
blocking mode.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</dl><!-- net -->
|
|
||||||
|
|
||||||
<dl id="net/http"><dt><a href="/pkg/net/http/">net/http</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 71272 -->
|
|
||||||
The <a href="/pkg/net/http/#Transport"><code>Transport</code></a> type has a
|
|
||||||
new <a href="/pkg/net/http/#Transport.MaxConnsPerHost"><code>MaxConnsPerHost</code></a>
|
|
||||||
option that permits limiting the maximum number of connections
|
|
||||||
per host.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 79919 -->
|
|
||||||
The <a href="/pkg/net/http/#Cookie"><code>Cookie</code></a> type has a new
|
|
||||||
<a href="/pkg/net/http/#Cookie.SameSite"><code>SameSite</code></a> field
|
|
||||||
(of new type also named
|
|
||||||
<a href="/pkg/net/http/#SameSite"><code>SameSite</code></a>) to represent the new cookie attribute recently supported by most browsers.
|
|
||||||
The <code>net/http</code>'s <code>Transport</code> does not use the <code>SameSite</code>
|
|
||||||
attribute itself, but the package supports parsing and serializing the
|
|
||||||
attribute for browsers to use.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 81778 -->
|
|
||||||
It is no longer allowed to reuse a <a href="/pkg/net/http/#Server"><code>Server</code></a>
|
|
||||||
after a call to
|
|
||||||
<a href="/pkg/net/http/#Server.Shutdown"><code>Shutdown</code></a> or
|
|
||||||
<a href="/pkg/net/http/#Server.Close"><code>Close</code></a>. It was never officially supported
|
|
||||||
in the past and had often surprising behavior. Now, all future calls to the server's <code>Serve</code>
|
|
||||||
methods will return errors after a shutdown or close.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<!-- CL 89275 was reverted before Go 1.11 -->
|
|
||||||
|
|
||||||
<p><!-- CL 93296 -->
|
|
||||||
The constant <code>StatusMisdirectedRequest</code> is now defined for HTTP status code 421.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 123875 -->
|
|
||||||
The HTTP server will no longer cancel contexts or send on
|
|
||||||
<a href="/pkg/net/http/#CloseNotifier"><code>CloseNotifier</code></a>
|
|
||||||
channels upon receiving pipelined HTTP/1.1 requests. Browsers do
|
|
||||||
not use HTTP pipelining, but some clients (such as
|
|
||||||
Debian's <code>apt</code>) may be configured to do so.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 115255 -->
|
|
||||||
<a href="/pkg/net/http/#ProxyFromEnvironment"><code>ProxyFromEnvironment</code></a>, which is used by the
|
|
||||||
<a href="/pkg/net/http/#DefaultTransport"><code>DefaultTransport</code></a>, now
|
|
||||||
supports CIDR notation and ports in the <code>NO_PROXY</code> environment variable.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</dl><!-- net/http -->
|
|
||||||
|
|
||||||
<dl id="net/http/httputil"><dt><a href="/pkg/net/http/httputil/">net/http/httputil</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 77410 -->
|
|
||||||
The
|
|
||||||
<a href="/pkg/net/http/httputil/#ReverseProxy"><code>ReverseProxy</code></a>
|
|
||||||
has a new
|
|
||||||
<a href="/pkg/net/http/httputil/#ReverseProxy.ErrorHandler"><code>ErrorHandler</code></a>
|
|
||||||
option to permit changing how errors are handled.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 115135 -->
|
|
||||||
The <code>ReverseProxy</code> now also passes
|
|
||||||
"<code>TE:</code> <code>trailers</code>" request headers
|
|
||||||
through to the backend, as required by the gRPC protocol.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</dl><!-- net/http/httputil -->
|
|
||||||
|
|
||||||
<dl id="os"><dt><a href="/pkg/os/">os</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 78835 -->
|
|
||||||
The new <a href="/pkg/os/#UserCacheDir"><code>UserCacheDir</code></a> function
|
|
||||||
returns the default root directory to use for user-specific cached data.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 94856 -->
|
|
||||||
The new <a href="/pkg/os/#ModeIrregular"><code>ModeIrregular</code></a>
|
|
||||||
is a <a href="/pkg/os/#FileMode"><code>FileMode</code></a> bit to represent
|
|
||||||
that a file is not a regular file, but nothing else is known about it, or that
|
|
||||||
it's not a socket, device, named pipe, symlink, or other file type for which
|
|
||||||
Go has a defined mode bit.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 99337 -->
|
|
||||||
<a href="/pkg/os/#Symlink"><code>Symlink</code></a> now works
|
|
||||||
for unprivileged users on Windows 10 on machines with Developer
|
|
||||||
Mode enabled.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 100077 -->
|
|
||||||
When a non-blocking descriptor is passed
|
|
||||||
to <a href="/pkg/os#NewFile"><code>NewFile</code></a>, the
|
|
||||||
resulting <code>*File</code> will be kept in non-blocking
|
|
||||||
mode. This means that I/O for that <code>*File</code> will use
|
|
||||||
the runtime poller rather than a separate thread, and that
|
|
||||||
the <a href="/pkg/os/#File.SetDeadline"><code>SetDeadline</code></a>
|
|
||||||
methods will work.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</dl><!-- os -->
|
|
||||||
|
|
||||||
<dl id="os/signal"><dt><a href="/pkg/os/signal/">os/signal</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 108376 -->
|
|
||||||
The new <a href="/pkg/os/signal/#Ignored"><code>Ignored</code></a> function reports
|
|
||||||
whether a signal is currently ignored.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</dl><!-- os/signal -->
|
|
||||||
|
|
||||||
<dl id="os/user"><dt><a href="/pkg/os/user/">os/user</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 92456 -->
|
|
||||||
The <code>os/user</code> package can now be built in pure Go
|
|
||||||
mode using the build tag "<code>osusergo</code>",
|
|
||||||
independent of the use of the environment
|
|
||||||
variable <code>CGO_ENABLED=0</code>. Previously the only way to use
|
|
||||||
the package's pure Go implementation was to disable <code>cgo</code>
|
|
||||||
support across the entire program.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</dl><!-- os/user -->
|
|
||||||
|
|
||||||
<!-- CL 101715 was reverted -->
|
|
||||||
|
|
||||||
<dl id="pkg-runtime"><dt id="runtime-again"><a href="/pkg/runtime/">runtime</a></dt>
|
|
||||||
<dd>
|
|
||||||
|
|
||||||
<p><!-- CL 70993 -->
|
|
||||||
Setting the <code>GODEBUG=tracebackancestors=<em>N</em></code>
|
|
||||||
environment variable now extends tracebacks with the stacks at
|
|
||||||
which goroutines were created, where <em>N</em> limits the
|
|
||||||
number of ancestor goroutines to report.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</dl><!-- runtime -->
|
|
||||||
|
|
||||||
<dl id="runtime/pprof"><dt><a href="/pkg/runtime/pprof/">runtime/pprof</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 102696 -->
|
|
||||||
This release adds a new "allocs" profile type that profiles
|
|
||||||
total number of bytes allocated since the program began
|
|
||||||
(including garbage-collected bytes). This is identical to the
|
|
||||||
existing "heap" profile viewed in <code>-alloc_space</code> mode.
|
|
||||||
Now <code>go test -memprofile=...</code> reports an "allocs" profile
|
|
||||||
instead of "heap" profile.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</dl><!-- runtime/pprof -->
|
|
||||||
|
|
||||||
<dl id="sync"><dt><a href="/pkg/sync/">sync</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 87095 -->
|
|
||||||
The mutex profile now includes reader/writer contention
|
|
||||||
for <a href="/pkg/sync/#RWMutex"><code>RWMutex</code></a>.
|
|
||||||
Writer/writer contention was already included in the mutex
|
|
||||||
profile.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</dl><!-- sync -->
|
|
||||||
|
|
||||||
<dl id="syscall"><dt><a href="/pkg/syscall/">syscall</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 106275 -->
|
|
||||||
On Windows, several fields were changed from <code>uintptr</code> to a new
|
|
||||||
<a href="/pkg/syscall/?GOOS=windows&GOARCH=amd64#Pointer"><code>Pointer</code></a>
|
|
||||||
type to avoid problems with Go's garbage collector. The same change was made
|
|
||||||
to the <a href="https://godoc.org/golang.org/x/sys/windows"><code>golang.org/x/sys/windows</code></a>
|
|
||||||
package. For any code affected, users should first migrate away from the <code>syscall</code>
|
|
||||||
package to the <code>golang.org/x/sys/windows</code> package, and then change
|
|
||||||
to using the <code>Pointer</code>, while obeying the
|
|
||||||
<a href="/pkg/unsafe/#Pointer"><code>unsafe.Pointer</code> conversion rules</a>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 118658 -->
|
|
||||||
On Linux, the <code>flags</code> parameter to
|
|
||||||
<a href="/pkg/syscall/?GOOS=linux&GOARCH=amd64#Faccessat"><code>Faccessat</code></a>
|
|
||||||
is now implemented just as in glibc. In earlier Go releases the
|
|
||||||
flags parameter was ignored.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 118658 -->
|
|
||||||
On Linux, the <code>flags</code> parameter to
|
|
||||||
<a href="/pkg/syscall/?GOOS=linux&GOARCH=amd64#Fchmodat"><code>Fchmodat</code></a>
|
|
||||||
is now validated. Linux's <code>fchmodat</code> doesn't support the <code>flags</code> parameter
|
|
||||||
so we now mimic glibc's behavior and return an error if it's non-zero.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</dl><!-- syscall -->
|
|
||||||
|
|
||||||
<dl id="text/scanner"><dt><a href="/pkg/text/scanner/">text/scanner</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 112037 -->
|
|
||||||
The <a href="/pkg/text/scanner/#Scanner.Scan"><code>Scanner.Scan</code></a> method now returns
|
|
||||||
the <a href="/pkg/text/scanner/#RawString"><code>RawString</code></a> token
|
|
||||||
instead of <a href="/pkg/text/scanner/#String"><code>String</code></a>
|
|
||||||
for raw string literals.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</dl><!-- text/scanner -->
|
|
||||||
|
|
||||||
<dl id="text/template"><dt><a href="/pkg/text/template/">text/template</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 84480 -->
|
|
||||||
Modifying template variables via assignments is now permitted via the <code>=</code> token:
|
|
||||||
</p>
|
|
||||||
<pre>
|
|
||||||
{{"{{"}} $v := "init" {{"}}"}}
|
|
||||||
{{"{{"}} if true {{"}}"}}
|
|
||||||
{{"{{"}} $v = "changed" {{"}}"}}
|
|
||||||
{{"{{"}} end {{"}}"}}
|
|
||||||
v: {{"{{"}} $v {{"}}"}} {{"{{"}}/* "changed" */{{"}}"}}</pre>
|
|
||||||
|
|
||||||
<p><!-- CL 95215 -->
|
|
||||||
In previous versions untyped <code>nil</code> values passed to
|
|
||||||
template functions were ignored. They are now passed as normal
|
|
||||||
arguments.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</dl><!-- text/template -->
|
|
||||||
|
|
||||||
<dl id="time"><dt><a href="/pkg/time/">time</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 98157 -->
|
|
||||||
Parsing of timezones denoted by sign and offset is now
|
|
||||||
supported. In previous versions, numeric timezone names
|
|
||||||
(such as <code>+03</code>) were not considered valid, and only
|
|
||||||
three-letter abbreviations (such as <code>MST</code>) were accepted
|
|
||||||
when expecting a timezone name.
|
|
||||||
</p>
|
|
||||||
</dl><!-- time -->
|
|
949
doc/go1.12.html
|
@ -1,949 +0,0 @@
|
||||||
<!--{
|
|
||||||
"Title": "Go 1.12 Release Notes",
|
|
||||||
"Path": "/doc/go1.12",
|
|
||||||
"Template": true
|
|
||||||
}-->
|
|
||||||
|
|
||||||
<!--
|
|
||||||
NOTE: In this document and others in this directory, the convention is to
|
|
||||||
set fixed-width phrases with non-fixed-width spaces, as in
|
|
||||||
<code>hello</code> <code>world</code>.
|
|
||||||
Do not send CLs removing the interior tags from such phrases.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<style>
|
|
||||||
main ul li { margin: 0.5em 0; }
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<h2 id="introduction">Introduction to Go 1.12</h2>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
The latest Go release, version 1.12, arrives six months after <a href="go1.11">Go 1.11</a>.
|
|
||||||
Most of its changes are in the implementation of the toolchain, runtime, and libraries.
|
|
||||||
As always, the release maintains the Go 1 <a href="/doc/go1compat">promise of compatibility</a>.
|
|
||||||
We expect almost all Go programs to continue to compile and run as before.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h2 id="language">Changes to the language</h2>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
There are no changes to the language specification.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h2 id="ports">Ports</h2>
|
|
||||||
|
|
||||||
<p><!-- CL 138675 -->
|
|
||||||
The race detector is now supported on <code>linux/arm64</code>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p id="freebsd">
|
|
||||||
Go 1.12 is the last release that is supported on FreeBSD 10.x, which has
|
|
||||||
already reached end-of-life. Go 1.13 will require FreeBSD 11.2+ or FreeBSD
|
|
||||||
12.0+.
|
|
||||||
FreeBSD 12.0+ requires a kernel with the COMPAT_FREEBSD11 option set (this is the default).
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 146898 -->
|
|
||||||
cgo is now supported on <code>linux/ppc64</code>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p id="hurd"><!-- CL 146023 -->
|
|
||||||
<code>hurd</code> is now a recognized value for <code>GOOS</code>, reserved
|
|
||||||
for the GNU/Hurd system for use with <code>gccgo</code>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h3 id="windows">Windows</h3>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Go's new <code>windows/arm</code> port supports running Go on Windows 10
|
|
||||||
IoT Core on 32-bit ARM chips such as the Raspberry Pi 3.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h3 id="aix">AIX</h3>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Go now supports AIX 7.2 and later on POWER8 architectures (<code>aix/ppc64</code>). External linking, cgo, pprof and the race detector aren't yet supported.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h3 id="darwin">Darwin</h3>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Go 1.12 is the last release that will run on macOS 10.10 Yosemite.
|
|
||||||
Go 1.13 will require macOS 10.11 El Capitan or later.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 141639 -->
|
|
||||||
<code>libSystem</code> is now used when making syscalls on Darwin,
|
|
||||||
ensuring forward-compatibility with future versions of macOS and iOS.
|
|
||||||
<!-- CL 153338 -->
|
|
||||||
The switch to <code>libSystem</code> triggered additional App Store
|
|
||||||
checks for private API usage. Since it is considered private,
|
|
||||||
<code>syscall.Getdirentries</code> now always fails with
|
|
||||||
<code>ENOSYS</code> on iOS.
|
|
||||||
Additionally, <a href="/pkg/syscall/#Setrlimit"><code>syscall.Setrlimit</code></a>
|
|
||||||
reports <code>invalid</code> <code>argument</code> in places where it historically
|
|
||||||
succeeded. These consequences are not specific to Go and users should expect
|
|
||||||
behavioral parity with <code>libSystem</code>'s implementation going forward.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h2 id="tools">Tools</h2>
|
|
||||||
|
|
||||||
<h3 id="vet"><code>go tool vet</code> no longer supported</h3>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
The <code>go vet</code> command has been rewritten to serve as the
|
|
||||||
base for a range of different source code analysis tools. See
|
|
||||||
the <a href="https://godoc.org/golang.org/x/tools/go/analysis">golang.org/x/tools/go/analysis</a>
|
|
||||||
package for details. A side-effect is that <code>go tool vet</code>
|
|
||||||
is no longer supported. External tools that use <code>go tool
|
|
||||||
vet</code> must be changed to use <code>go
|
|
||||||
vet</code>. Using <code>go vet</code> instead of <code>go tool
|
|
||||||
vet</code> should work with all supported versions of Go.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
As part of this change, the experimental <code>-shadow</code> option
|
|
||||||
is no longer available with <code>go vet</code>. Checking for
|
|
||||||
variable shadowing may now be done using
|
|
||||||
<pre>
|
|
||||||
go get -u golang.org/x/tools/go/analysis/passes/shadow/cmd/shadow
|
|
||||||
go vet -vettool=$(which shadow)
|
|
||||||
</pre>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h3 id="tour">Tour</h3>
|
|
||||||
|
|
||||||
<p> <!-- CL 152657 -->
|
|
||||||
The Go tour is no longer included in the main binary distribution. To
|
|
||||||
run the tour locally, instead of running <code>go</code> <code>tool</code> <code>tour</code>,
|
|
||||||
manually install it:
|
|
||||||
<pre>
|
|
||||||
go get -u golang.org/x/tour
|
|
||||||
tour
|
|
||||||
</pre>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h3 id="gocache">Build cache requirement</h3>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
The <a href="/cmd/go/#hdr-Build_and_test_caching">build cache</a> is now
|
|
||||||
required as a step toward eliminating
|
|
||||||
<code>$GOPATH/pkg</code>. Setting the environment variable
|
|
||||||
<code>GOCACHE=off</code> will cause <code>go</code> commands that write to the
|
|
||||||
cache to fail.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h3 id="binary-only">Binary-only packages</h3>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Go 1.12 is the last release that will support binary-only packages.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h3 id="cgo">Cgo</h3>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Go 1.12 will translate the C type <code>EGLDisplay</code> to the Go type <code>uintptr</code>.
|
|
||||||
This change is similar to how Go 1.10 and newer treats Darwin's CoreFoundation
|
|
||||||
and Java's JNI types. See the
|
|
||||||
<a href="/cmd/cgo/#hdr-Special_cases">cgo documentation</a>
|
|
||||||
for more information.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 152657 -->
|
|
||||||
Mangled C names are no longer accepted in packages that use Cgo. Use the Cgo
|
|
||||||
names instead. For example, use the documented cgo name <code>C.char</code>
|
|
||||||
rather than the mangled name <code>_Ctype_char</code> that cgo generates.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h3 id="modules">Modules</h3>
|
|
||||||
|
|
||||||
<p><!-- CL 148517 -->
|
|
||||||
When <code>GO111MODULE</code> is set to <code>on</code>, the <code>go</code>
|
|
||||||
command now supports module-aware operations outside of a module directory,
|
|
||||||
provided that those operations do not need to resolve import paths relative to
|
|
||||||
the current directory or explicitly edit the <code>go.mod</code> file.
|
|
||||||
Commands such as <code>go</code> <code>get</code>,
|
|
||||||
<code>go</code> <code>list</code>, and
|
|
||||||
<code>go</code> <code>mod</code> <code>download</code> behave as if in a
|
|
||||||
module with initially-empty requirements.
|
|
||||||
In this mode, <code>go</code> <code>env</code> <code>GOMOD</code> reports
|
|
||||||
the system's null device (<code>/dev/null</code> or <code>NUL</code>).
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 146382 -->
|
|
||||||
<code>go</code> commands that download and extract modules are now safe to
|
|
||||||
invoke concurrently.
|
|
||||||
The module cache (<code>GOPATH/pkg/mod</code>) must reside in a filesystem that
|
|
||||||
supports file locking.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 147282, 147281 -->
|
|
||||||
The <code>go</code> directive in a <code>go.mod</code> file now indicates the
|
|
||||||
version of the language used by the files within that module.
|
|
||||||
It will be set to the current release
|
|
||||||
(<code>go</code> <code>1.12</code>) if no existing version is
|
|
||||||
present.
|
|
||||||
If the <code>go</code> directive for a module specifies a
|
|
||||||
version <em>newer</em> than the toolchain in use, the <code>go</code> command
|
|
||||||
will attempt to build the packages regardless, and will note the mismatch only if
|
|
||||||
that build fails.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 147282, 147281 -->
|
|
||||||
This changed use of the <code>go</code> directive means that if you
|
|
||||||
use Go 1.12 to build a module, thus recording <code>go 1.12</code>
|
|
||||||
in the <code>go.mod</code> file, you will get an error when
|
|
||||||
attempting to build the same module with Go 1.11 through Go 1.11.3.
|
|
||||||
Go 1.11.4 or later will work fine, as will releases older than Go 1.11.
|
|
||||||
If you must use Go 1.11 through 1.11.3, you can avoid the problem by
|
|
||||||
setting the language version to 1.11, using the Go 1.12 go tool,
|
|
||||||
via <code>go mod edit -go=1.11</code>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 152739 -->
|
|
||||||
When an import cannot be resolved using the active modules,
|
|
||||||
the <code>go</code> command will now try to use the modules mentioned in the
|
|
||||||
main module's <code>replace</code> directives before consulting the module
|
|
||||||
cache and the usual network sources.
|
|
||||||
If a matching replacement is found but the <code>replace</code> directive does
|
|
||||||
not specify a version, the <code>go</code> command uses a pseudo-version
|
|
||||||
derived from the zero <code>time.Time</code> (such
|
|
||||||
as <code>v0.0.0-00010101000000-000000000000</code>).
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h3 id="compiler">Compiler toolchain</h3>
|
|
||||||
|
|
||||||
<p><!-- CL 134155, 134156 -->
|
|
||||||
The compiler's live variable analysis has improved. This may mean that
|
|
||||||
finalizers will be executed sooner in this release than in previous
|
|
||||||
releases. If that is a problem, consider the appropriate addition of a
|
|
||||||
<a href="/pkg/runtime/#KeepAlive"><code>runtime.KeepAlive</code></a> call.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 147361 -->
|
|
||||||
More functions are now eligible for inlining by default, including
|
|
||||||
functions that do nothing but call another function.
|
|
||||||
This extra inlining makes it additionally important to use
|
|
||||||
<a href="/pkg/runtime/#CallersFrames"><code>runtime.CallersFrames</code></a>
|
|
||||||
instead of iterating over the result of
|
|
||||||
<a href="/pkg/runtime/#Callers"><code>runtime.Callers</code></a> directly.
|
|
||||||
<pre>
|
|
||||||
// Old code which no longer works correctly (it will miss inlined call frames).
|
|
||||||
var pcs [10]uintptr
|
|
||||||
n := runtime.Callers(1, pcs[:])
|
|
||||||
for _, pc := range pcs[:n] {
|
|
||||||
f := runtime.FuncForPC(pc)
|
|
||||||
if f != nil {
|
|
||||||
fmt.Println(f.Name())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</pre>
|
|
||||||
<pre>
|
|
||||||
// New code which will work correctly.
|
|
||||||
var pcs [10]uintptr
|
|
||||||
n := runtime.Callers(1, pcs[:])
|
|
||||||
frames := runtime.CallersFrames(pcs[:n])
|
|
||||||
for {
|
|
||||||
frame, more := frames.Next()
|
|
||||||
fmt.Println(frame.Function)
|
|
||||||
if !more {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</pre>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 153477 -->
|
|
||||||
Wrappers generated by the compiler to implement method expressions
|
|
||||||
are no longer reported
|
|
||||||
by <a href="/pkg/runtime/#CallersFrames"><code>runtime.CallersFrames</code></a>
|
|
||||||
and <a href="/pkg/runtime/#Stack"><code>runtime.Stack</code></a>. They
|
|
||||||
are also not printed in panic stack traces.
|
|
||||||
|
|
||||||
This change aligns the <code>gc</code> toolchain to match
|
|
||||||
the <code>gccgo</code> toolchain, which already elided such wrappers
|
|
||||||
from stack traces.
|
|
||||||
|
|
||||||
Clients of these APIs might need to adjust for the missing
|
|
||||||
frames. For code that must interoperate between 1.11 and 1.12
|
|
||||||
releases, you can replace the method expression <code>x.M</code>
|
|
||||||
with the function literal <code>func (...) { x.M(...) } </code>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 144340 -->
|
|
||||||
The compiler now accepts a <code>-lang</code> flag to set the Go language
|
|
||||||
version to use. For example, <code>-lang=go1.8</code> causes the compiler to
|
|
||||||
emit an error if the program uses type aliases, which were added in Go 1.9.
|
|
||||||
Language changes made before Go 1.12 are not consistently enforced.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 147160 -->
|
|
||||||
The compiler toolchain now uses different conventions to call Go
|
|
||||||
functions and assembly functions. This should be invisible to users,
|
|
||||||
except for calls that simultaneously cross between Go and
|
|
||||||
assembly <em>and</em> cross a package boundary. If linking results
|
|
||||||
in an error like "relocation target not defined for ABIInternal (but
|
|
||||||
is defined for ABI0)", please refer to the
|
|
||||||
<a href="https://github.com/golang/proposal/blob/master/design/27539-internal-abi.md#compatibility">compatibility section</a>
|
|
||||||
of the ABI design document.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 145179 -->
|
|
||||||
There have been many improvements to the DWARF debug information
|
|
||||||
produced by the compiler, including improvements to argument
|
|
||||||
printing and variable location information.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 61511 -->
|
|
||||||
Go programs now also maintain stack frame pointers on <code>linux/arm64</code>
|
|
||||||
for the benefit of profiling tools like <code>perf</code>. The frame pointer
|
|
||||||
maintenance has a small run-time overhead that varies but averages around 3%.
|
|
||||||
To build a toolchain that does not use frame pointers, set
|
|
||||||
<code>GOEXPERIMENT=noframepointer</code> when running <code>make.bash</code>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 142717 -->
|
|
||||||
The obsolete "safe" compiler mode (enabled by the <code>-u</code> gcflag) has been removed.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h3 id="godoc"><code>godoc</code> and <code>go</code> <code>doc</code></h3>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
In Go 1.12, <code>godoc</code> no longer has a command-line interface and
|
|
||||||
is only a web server. Users should use <code>go</code> <code>doc</code>
|
|
||||||
for command-line help output instead. Go 1.12 is the last release that will
|
|
||||||
include the <code>godoc</code> webserver; in Go 1.13 it will be available
|
|
||||||
via <code>go</code> <code>get</code>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 141977 -->
|
|
||||||
<code>go</code> <code>doc</code> now supports the <code>-all</code> flag,
|
|
||||||
which will cause it to print all exported APIs and their documentation,
|
|
||||||
as the <code>godoc</code> command line used to do.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 140959 -->
|
|
||||||
<code>go</code> <code>doc</code> also now includes the <code>-src</code> flag,
|
|
||||||
which will show the target's source code.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h3 id="trace">Trace</h3>
|
|
||||||
|
|
||||||
<p><!-- CL 60790 -->
|
|
||||||
The trace tool now supports plotting mutator utilization curves,
|
|
||||||
including cross-references to the execution trace. These are useful
|
|
||||||
for analyzing the impact of the garbage collector on application
|
|
||||||
latency and throughput.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h3 id="assembler">Assembler</h3>
|
|
||||||
|
|
||||||
<p><!-- CL 147218 -->
|
|
||||||
On <code>arm64</code>, the platform register was renamed from
|
|
||||||
<code>R18</code> to <code>R18_PLATFORM</code> to prevent accidental
|
|
||||||
use, as the OS could choose to reserve this register.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h2 id="runtime">Runtime</h2>
|
|
||||||
|
|
||||||
<p><!-- CL 138959 -->
|
|
||||||
Go 1.12 significantly improves the performance of sweeping when a
|
|
||||||
large fraction of the heap remains live. This reduces allocation
|
|
||||||
latency immediately following a garbage collection.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 139719 -->
|
|
||||||
The Go runtime now releases memory back to the operating system more
|
|
||||||
aggressively, particularly in response to large allocations that
|
|
||||||
can't reuse existing heap space.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 146342, CL 146340, CL 146345, CL 146339, CL 146343, CL 146337, CL 146341, CL 146338 -->
|
|
||||||
The Go runtime's timer and deadline code is faster and scales better
|
|
||||||
with higher numbers of CPUs. In particular, this improves the
|
|
||||||
performance of manipulating network connection deadlines.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 135395 -->
|
|
||||||
On Linux, the runtime now uses <code>MADV_FREE</code> to release unused
|
|
||||||
memory. This is more efficient but may result in higher reported
|
|
||||||
RSS. The kernel will reclaim the unused data when it is needed.
|
|
||||||
To revert to the Go 1.11 behavior (<code>MADV_DONTNEED</code>), set the
|
|
||||||
environment variable <code>GODEBUG=madvdontneed=1</code>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 149578 -->
|
|
||||||
Adding cpu.<em>extension</em>=off to the
|
|
||||||
<a href="/doc/diagnostics.html#godebug">GODEBUG</a> environment
|
|
||||||
variable now disables the use of optional CPU instruction
|
|
||||||
set extensions in the standard library and runtime. This is not
|
|
||||||
yet supported on Windows.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 158337 -->
|
|
||||||
Go 1.12 improves the accuracy of memory profiles by fixing
|
|
||||||
overcounting of large heap allocations.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 159717 -->
|
|
||||||
Tracebacks, <code>runtime.Caller</code>,
|
|
||||||
and <code>runtime.Callers</code> no longer include
|
|
||||||
compiler-generated initialization functions. Doing a traceback
|
|
||||||
during the initialization of a global variable will now show a
|
|
||||||
function named <code>PKG.init.ializers</code>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h2 id="library">Core library</h2>
|
|
||||||
|
|
||||||
<h3 id="tls_1_3">TLS 1.3</h3>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Go 1.12 adds opt-in support for TLS 1.3 in the <code>crypto/tls</code> package as
|
|
||||||
specified by <a href="https://www.rfc-editor.org/info/rfc8446">RFC 8446</a>. It can
|
|
||||||
be enabled by adding the value <code>tls13=1</code> to the <code>GODEBUG</code>
|
|
||||||
environment variable. It will be enabled by default in Go 1.13.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
To negotiate TLS 1.3, make sure you do not set an explicit <code>MaxVersion</code> in
|
|
||||||
<a href="/pkg/crypto/tls/#Config"><code>Config</code></a> and run your program with
|
|
||||||
the environment variable <code>GODEBUG=tls13=1</code> set.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
All TLS 1.2 features except <code>TLSUnique</code> in
|
|
||||||
<a href="/pkg/crypto/tls/#ConnectionState"><code>ConnectionState</code></a>
|
|
||||||
and renegotiation are available in TLS 1.3 and provide equivalent or
|
|
||||||
better security and performance. Note that even though TLS 1.3 is backwards
|
|
||||||
compatible with previous versions, certain legacy systems might not work
|
|
||||||
correctly when attempting to negotiate it. RSA certificate keys too small
|
|
||||||
to be secure (including 512-bit keys) will not work with TLS 1.3.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
TLS 1.3 cipher suites are not configurable. All supported cipher suites are
|
|
||||||
safe, and if <code>PreferServerCipherSuites</code> is set in
|
|
||||||
<a href="/pkg/crypto/tls/#Config"><code>Config</code></a> the preference order
|
|
||||||
is based on the available hardware.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Early data (also called "0-RTT mode") is not currently supported as a
|
|
||||||
client or server. Additionally, a Go 1.12 server does not support skipping
|
|
||||||
unexpected early data if a client sends it. Since TLS 1.3 0-RTT mode
|
|
||||||
involves clients keeping state regarding which servers support 0-RTT,
|
|
||||||
a Go 1.12 server cannot be part of a load-balancing pool where some other
|
|
||||||
servers do support 0-RTT. If switching a domain from a server that supported
|
|
||||||
0-RTT to a Go 1.12 server, 0-RTT would have to be disabled for at least the
|
|
||||||
lifetime of the issued session tickets before the switch to ensure
|
|
||||||
uninterrupted operation.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
In TLS 1.3 the client is the last one to speak in the handshake, so if it causes
|
|
||||||
an error to occur on the server, it will be returned on the client by the first
|
|
||||||
<a href="/pkg/crypto/tls/#Conn.Read"><code>Read</code></a>, not by
|
|
||||||
<a href="/pkg/crypto/tls/#Conn.Handshake"><code>Handshake</code></a>. For
|
|
||||||
example, that will be the case if the server rejects the client certificate.
|
|
||||||
Similarly, session tickets are now post-handshake messages, so are only
|
|
||||||
received by the client upon its first
|
|
||||||
<a href="/pkg/crypto/tls/#Conn.Read"><code>Read</code></a>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h3 id="minor_library_changes">Minor changes to the library</h3>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
As always, there are various minor changes and updates to the library,
|
|
||||||
made with the Go 1 <a href="/doc/go1compat">promise of compatibility</a>
|
|
||||||
in mind.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<!-- TODO: CL 115677: https://golang.org/cl/115677: cmd/vet: check embedded field tags too -->
|
|
||||||
|
|
||||||
<dl id="bufio"><dt><a href="/pkg/bufio/">bufio</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 149297 -->
|
|
||||||
<code>Reader</code>'s <a href="/pkg/bufio/#Reader.UnreadRune"><code>UnreadRune</code></a> and
|
|
||||||
<a href="/pkg/bufio/#Reader.UnreadByte"><code>UnreadByte</code></a> methods will now return an error
|
|
||||||
if they are called after <a href="/pkg/bufio/#Reader.Peek"><code>Peek</code></a>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</dl><!-- bufio -->
|
|
||||||
|
|
||||||
<dl id="bytes"><dt><a href="/pkg/bytes/">bytes</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 137855 -->
|
|
||||||
The new function <a href="/pkg/bytes/#ReplaceAll"><code>ReplaceAll</code></a> returns a copy of
|
|
||||||
a byte slice with all non-overlapping instances of a value replaced by another.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 145098 -->
|
|
||||||
A pointer to a zero-value <a href="/pkg/bytes/#Reader"><code>Reader</code></a> is now
|
|
||||||
functionally equivalent to <a href="/pkg/bytes/#NewReader"><code>NewReader</code></a><code>(nil)</code>.
|
|
||||||
Prior to Go 1.12, the former could not be used as a substitute for the latter in all cases.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</dl><!-- bytes -->
|
|
||||||
|
|
||||||
<dl id="crypto/rand"><dt><a href="/pkg/crypto/rand/">crypto/rand</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 139419 -->
|
|
||||||
A warning will now be printed to standard error the first time
|
|
||||||
<code>Reader.Read</code> is blocked for more than 60 seconds waiting
|
|
||||||
to read entropy from the kernel.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 120055 -->
|
|
||||||
On FreeBSD, <code>Reader</code> now uses the <code>getrandom</code>
|
|
||||||
system call if available, <code>/dev/urandom</code> otherwise.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</dl><!-- crypto/rand -->
|
|
||||||
|
|
||||||
<dl id="crypto/rc4"><dt><a href="/pkg/crypto/rc4/">crypto/rc4</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 130397 -->
|
|
||||||
This release removes the assembly implementations, leaving only
|
|
||||||
the pure Go version. The Go compiler generates code that is
|
|
||||||
either slightly better or slightly worse, depending on the exact
|
|
||||||
CPU. RC4 is insecure and should only be used for compatibility
|
|
||||||
with legacy systems.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</dl><!-- crypto/rc4 -->
|
|
||||||
|
|
||||||
<dl id="crypto/tls"><dt><a href="/pkg/crypto/tls/">crypto/tls</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 143177 -->
|
|
||||||
If a client sends an initial message that does not look like TLS, the server
|
|
||||||
will no longer reply with an alert, and it will expose the underlying
|
|
||||||
<code>net.Conn</code> in the new field <code>Conn</code> of
|
|
||||||
<a href="/pkg/crypto/tls/#RecordHeaderError"><code>RecordHeaderError</code></a>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</dl><!-- crypto/tls -->
|
|
||||||
|
|
||||||
<dl id="database/sql"><dt><a href="/pkg/database/sql/">database/sql</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 145738 -->
|
|
||||||
A query cursor can now be obtained by passing a
|
|
||||||
<a href="/pkg/database/sql/#Rows"><code>*Rows</code></a>
|
|
||||||
value to the <a href="/pkg/database/sql/#Row.Scan"><code>Row.Scan</code></a> method.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</dl><!-- database/sql -->
|
|
||||||
|
|
||||||
<dl id="expvar"><dt><a href="/pkg/expvar/">expvar</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 139537 -->
|
|
||||||
The new <a href="/pkg/expvar/#Map.Delete"><code>Delete</code></a> method allows
|
|
||||||
for deletion of key/value pairs from a <a href="/pkg/expvar/#Map"><code>Map</code></a>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</dl><!-- expvar -->
|
|
||||||
|
|
||||||
<dl id="fmt"><dt><a href="/pkg/fmt/">fmt</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 142737 -->
|
|
||||||
Maps are now printed in key-sorted order to ease testing. The ordering rules are:
|
|
||||||
<ul>
|
|
||||||
<li>When applicable, nil compares low
|
|
||||||
<li>ints, floats, and strings order by <
|
|
||||||
<li>NaN compares less than non-NaN floats
|
|
||||||
<li>bool compares false before true
|
|
||||||
<li>Complex compares real, then imaginary
|
|
||||||
<li>Pointers compare by machine address
|
|
||||||
<li>Channel values compare by machine address
|
|
||||||
<li>Structs compare each field in turn
|
|
||||||
<li>Arrays compare each element in turn
|
|
||||||
<li>Interface values compare first by <code>reflect.Type</code> describing the concrete type
|
|
||||||
and then by concrete value as described in the previous rules.
|
|
||||||
</ul>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 129777 -->
|
|
||||||
When printing maps, non-reflexive key values like <code>NaN</code> were previously
|
|
||||||
displayed as <code><nil></code>. As of this release, the correct values are printed.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</dl><!-- fmt -->
|
|
||||||
|
|
||||||
<dl id="go/doc"><dt><a href="/pkg/go/doc/">go/doc</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 140958 -->
|
|
||||||
To address some outstanding issues in <a href="/cmd/doc/"><code>cmd/doc</code></a>,
|
|
||||||
this package has a new <a href="/pkg/go/doc/#Mode"><code>Mode</code></a> bit,
|
|
||||||
<code>PreserveAST</code>, which controls whether AST data is cleared.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</dl><!-- go/doc -->
|
|
||||||
|
|
||||||
<dl id="go/token"><dt><a href="/pkg/go/token/">go/token</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 134075 -->
|
|
||||||
The <a href="/pkg/go/token#File"><code>File</code></a> type has a new
|
|
||||||
<a href="/pkg/go/token#File.LineStart"><code>LineStart</code></a> field,
|
|
||||||
which returns the position of the start of a given line. This is especially useful
|
|
||||||
in programs that occasionally handle non-Go files, such as assembly, but wish to use
|
|
||||||
the <code>token.Pos</code> mechanism to identify file positions.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</dl><!-- go/token -->
|
|
||||||
|
|
||||||
<dl id="image"><dt><a href="/pkg/image/">image</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 118755 -->
|
|
||||||
The <a href="/pkg/image/#RegisterFormat"><code>RegisterFormat</code></a> function is now safe for concurrent use.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</dl><!-- image -->
|
|
||||||
|
|
||||||
<dl id="image/png"><dt><a href="/pkg/image/png/">image/png</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 134235 -->
|
|
||||||
Paletted images with fewer than 16 colors now encode to smaller outputs.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</dl><!-- image/png -->
|
|
||||||
|
|
||||||
<dl id="io"><dt><a href="/pkg/io/">io</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 139457 -->
|
|
||||||
The new <a href="/pkg/io#StringWriter"><code>StringWriter</code></a> interface wraps the
|
|
||||||
<a href="/pkg/io/#WriteString"><code>WriteString</code></a> function.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</dl><!-- io -->
|
|
||||||
|
|
||||||
<dl id="math"><dt><a href="/pkg/math/">math</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 153059 -->
|
|
||||||
The functions
|
|
||||||
<a href="/pkg/math/#Sin"><code>Sin</code></a>,
|
|
||||||
<a href="/pkg/math/#Cos"><code>Cos</code></a>,
|
|
||||||
<a href="/pkg/math/#Tan"><code>Tan</code></a>,
|
|
||||||
and <a href="/pkg/math/#Sincos"><code>Sincos</code></a> now
|
|
||||||
apply Payne-Hanek range reduction to huge arguments. This
|
|
||||||
produces more accurate answers, but they will not be bit-for-bit
|
|
||||||
identical with the results in earlier releases.
|
|
||||||
</p>
|
|
||||||
</dl><!-- math -->
|
|
||||||
|
|
||||||
<dl id="math/bits"><dt><a href="/pkg/math/bits/">math/bits</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 123157 -->
|
|
||||||
New extended precision operations <a href="/pkg/math/bits/#Add"><code>Add</code></a>, <a href="/pkg/math/bits/#Sub"><code>Sub</code></a>, <a href="/pkg/math/bits/#Mul"><code>Mul</code></a>, and <a href="/pkg/math/bits/#Div"><code>Div</code></a> are available in <code>uint</code>, <code>uint32</code>, and <code>uint64</code> versions.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</dl><!-- math/bits -->
|
|
||||||
|
|
||||||
<dl id="net"><dt><a href="/pkg/net/">net</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 146659 -->
|
|
||||||
The
|
|
||||||
<a href="/pkg/net/#Dialer.DualStack"><code>Dialer.DualStack</code></a> setting is now ignored and deprecated;
|
|
||||||
RFC 6555 Fast Fallback ("Happy Eyeballs") is now enabled by default. To disable, set
|
|
||||||
<a href="/pkg/net/#Dialer.FallbackDelay"><code>Dialer.FallbackDelay</code></a> to a negative value.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 107196 -->
|
|
||||||
Similarly, TCP keep-alives are now enabled by default if
|
|
||||||
<a href="/pkg/net/#Dialer.KeepAlive"><code>Dialer.KeepAlive</code></a> is zero.
|
|
||||||
To disable, set it to a negative value.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 113997 -->
|
|
||||||
On Linux, the <a href="http://man7.org/linux/man-pages/man2/splice.2.html"><code>splice</code> system call</a> is now used when copying from a
|
|
||||||
<a href="/pkg/net/#UnixConn"><code>UnixConn</code></a> to a
|
|
||||||
<a href="/pkg/net/#TCPConn"><code>TCPConn</code></a>.
|
|
||||||
</p>
|
|
||||||
</dl><!-- net -->
|
|
||||||
|
|
||||||
<dl id="net/http"><dt><a href="/pkg/net/http/">net/http</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 143177 -->
|
|
||||||
The HTTP server now rejects misdirected HTTP requests to HTTPS servers with a plaintext "400 Bad Request" response.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 130115 -->
|
|
||||||
The new <a href="/pkg/net/http/#Client.CloseIdleConnections"><code>Client.CloseIdleConnections</code></a>
|
|
||||||
method calls the <code>Client</code>'s underlying <code>Transport</code>'s <code>CloseIdleConnections</code>
|
|
||||||
if it has one.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 145398 -->
|
|
||||||
The <a href="/pkg/net/http/#Transport"><code>Transport</code></a> no longer rejects HTTP responses which declare
|
|
||||||
HTTP Trailers but don't use chunked encoding. Instead, the declared trailers are now just ignored.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 152080 --> <!-- CL 151857 -->
|
|
||||||
The <a href="/pkg/net/http/#Transport"><code>Transport</code></a> no longer handles <code>MAX_CONCURRENT_STREAMS</code> values
|
|
||||||
advertised from HTTP/2 servers as strictly as it did during Go 1.10 and Go 1.11. The default behavior is now back
|
|
||||||
to how it was in Go 1.9: each connection to a server can have up to <code>MAX_CONCURRENT_STREAMS</code> requests
|
|
||||||
active and then new TCP connections are created as needed. In Go 1.10 and Go 1.11 the <code>http2</code> package
|
|
||||||
would block and wait for requests to finish instead of creating new connections.
|
|
||||||
To get the stricter behavior back, import the
|
|
||||||
<a href="https://godoc.org/golang.org/x/net/http2"><code>golang.org/x/net/http2</code></a> package
|
|
||||||
directly and set
|
|
||||||
<a href="https://godoc.org/golang.org/x/net/http2#Transport.StrictMaxConcurrentStreams"><code>Transport.StrictMaxConcurrentStreams</code></a> to
|
|
||||||
<code>true</code>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</dl><!-- net/http -->
|
|
||||||
|
|
||||||
<dl id="net/url"><dt><a href="/pkg/net/url/">net/url</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 159157, CL 160178 -->
|
|
||||||
<a href="/pkg/net/url/#Parse"><code>Parse</code></a>,
|
|
||||||
<a href="/pkg/net/url/#ParseRequestURI"><code>ParseRequestURI</code></a>,
|
|
||||||
and
|
|
||||||
<a href="/pkg/net/url/#URL.Parse"><code>URL.Parse</code></a>
|
|
||||||
now return an
|
|
||||||
error for URLs containing ASCII control characters, which includes NULL,
|
|
||||||
tab, and newlines.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</dl><!-- net/url -->
|
|
||||||
|
|
||||||
<dl id="net/http/httputil"><dt><a href="/pkg/net/http/httputil/">net/http/httputil</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 146437 -->
|
|
||||||
The <a href="/pkg/net/http/httputil/#ReverseProxy"><code>ReverseProxy</code></a> now automatically
|
|
||||||
proxies WebSocket requests.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</dl><!-- net/http/httputil -->
|
|
||||||
|
|
||||||
<dl id="os"><dt><a href="/pkg/os/">os</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 125443 -->
|
|
||||||
The new <a href="/pkg/os/#ProcessState.ExitCode"><code>ProcessState.ExitCode</code></a> method
|
|
||||||
returns the process's exit code.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 135075 -->
|
|
||||||
<code>ModeCharDevice</code> has been added to the <code>ModeType</code> bitmask, allowing for
|
|
||||||
<code>ModeDevice | ModeCharDevice</code> to be recovered when masking a
|
|
||||||
<a href="/pkg/os/#FileMode"><code>FileMode</code></a> with <code>ModeType</code>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 139418 -->
|
|
||||||
The new function <a href="/pkg/os/#UserHomeDir"><code>UserHomeDir</code></a> returns the
|
|
||||||
current user's home directory.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 146020 -->
|
|
||||||
<a href="/pkg/os/#RemoveAll"><code>RemoveAll</code></a> now supports paths longer than 4096 characters
|
|
||||||
on most Unix systems.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 130676 -->
|
|
||||||
<a href="/pkg/os/#File.Sync"><code>File.Sync</code></a> now uses <code>F_FULLFSYNC</code> on macOS
|
|
||||||
to correctly flush the file contents to permanent storage.
|
|
||||||
This may cause the method to run more slowly than in previous releases.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!--CL 155517 -->
|
|
||||||
<a href="/pkg/os/#File"><code>File</code></a> now supports
|
|
||||||
a <a href="/pkg/os/#File.SyscallConn"><code>SyscallConn</code></a>
|
|
||||||
method returning
|
|
||||||
a <a href="/pkg/syscall/#RawConn"><code>syscall.RawConn</code></a>
|
|
||||||
interface value. This may be used to invoke system-specific
|
|
||||||
operations on the underlying file descriptor.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</dl><!-- os -->
|
|
||||||
|
|
||||||
<dl id="path/filepath"><dt><a href="/pkg/path/filepath/">path/filepath</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 145220 -->
|
|
||||||
The <a href="/pkg/path/filepath/#IsAbs"><code>IsAbs</code></a> function now returns true when passed
|
|
||||||
a reserved filename on Windows such as <code>NUL</code>.
|
|
||||||
<a href="https://docs.microsoft.com/en-us/windows/desktop/fileio/naming-a-file#naming-conventions">List of reserved names.</a>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</dl><!-- path/filepath -->
|
|
||||||
|
|
||||||
<dl id="reflect"><dt><a href="/pkg/reflect/">reflect</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 33572 -->
|
|
||||||
A new <a href="/pkg/reflect#MapIter"><code>MapIter</code></a> type is
|
|
||||||
an iterator for ranging over a map. This type is exposed through the
|
|
||||||
<a href="/pkg/reflect#Value"><code>Value</code></a> type's new
|
|
||||||
<a href="/pkg/reflect#Value.MapRange"><code>MapRange</code></a> method.
|
|
||||||
This follows the same iteration semantics as a range statement, with <code>Next</code>
|
|
||||||
to advance the iterator, and <code>Key</code>/<code>Value</code> to access each entry.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</dl><!-- reflect -->
|
|
||||||
|
|
||||||
<dl id="regexp"><dt><a href="/pkg/regexp/">regexp</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 139784 -->
|
|
||||||
<a href="/pkg/regexp/#Regexp.Copy"><code>Copy</code></a> is no longer necessary
|
|
||||||
to avoid lock contention, so it has been given a partial deprecation comment.
|
|
||||||
<a href="/pkg/regexp/#Regexp.Copy"><code>Copy</code></a>
|
|
||||||
may still be appropriate if the reason for its use is to make two copies with
|
|
||||||
different <a href="/pkg/regexp/#Regexp.Longest"><code>Longest</code></a> settings.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</dl><!-- regexp -->
|
|
||||||
|
|
||||||
<dl id="runtime/debug"><dt><a href="/pkg/runtime/debug/">runtime/debug</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 144220 -->
|
|
||||||
A new <a href="/pkg/runtime/debug/#BuildInfo"><code>BuildInfo</code></a> type
|
|
||||||
exposes the build information read from the running binary, available only in
|
|
||||||
binaries built with module support. This includes the main package path, main
|
|
||||||
module information, and the module dependencies. This type is given through the
|
|
||||||
<a href="/pkg/runtime/debug/#ReadBuildInfo"><code>ReadBuildInfo</code></a> function
|
|
||||||
on <a href="/pkg/runtime/debug/#BuildInfo"><code>BuildInfo</code></a>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</dl><!-- runtime/debug -->
|
|
||||||
|
|
||||||
<dl id="strings"><dt><a href="/pkg/strings/">strings</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 137855 -->
|
|
||||||
The new function <a href="/pkg/strings/#ReplaceAll"><code>ReplaceAll</code></a> returns a copy of
|
|
||||||
a string with all non-overlapping instances of a value replaced by another.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 145098 -->
|
|
||||||
A pointer to a zero-value <a href="/pkg/strings/#Reader"><code>Reader</code></a> is now
|
|
||||||
functionally equivalent to <a href="/pkg/strings/#NewReader"><code>NewReader</code></a><code>(nil)</code>.
|
|
||||||
Prior to Go 1.12, the former could not be used as a substitute for the latter in all cases.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 122835 -->
|
|
||||||
The new <a href="/pkg/strings/#Builder.Cap"><code>Builder.Cap</code></a> method returns the capacity of the builder's underlying byte slice.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 131495 -->
|
|
||||||
The character mapping functions <a href="/pkg/strings/#Map"><code>Map</code></a>,
|
|
||||||
<a href="/pkg/strings/#Title"><code>Title</code></a>,
|
|
||||||
<a href="/pkg/strings/#ToLower"><code>ToLower</code></a>,
|
|
||||||
<a href="/pkg/strings/#ToLowerSpecial"><code>ToLowerSpecial</code></a>,
|
|
||||||
<a href="/pkg/strings/#ToTitle"><code>ToTitle</code></a>,
|
|
||||||
<a href="/pkg/strings/#ToTitleSpecial"><code>ToTitleSpecial</code></a>,
|
|
||||||
<a href="/pkg/strings/#ToUpper"><code>ToUpper</code></a>, and
|
|
||||||
<a href="/pkg/strings/#ToUpperSpecial"><code>ToUpperSpecial</code></a>
|
|
||||||
now always guarantee to return valid UTF-8. In earlier releases, if the input was invalid UTF-8 but no character replacements
|
|
||||||
needed to be applied, these routines incorrectly returned the invalid UTF-8 unmodified.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</dl><!-- strings -->
|
|
||||||
|
|
||||||
<dl id="syscall"><dt><a href="/pkg/syscall/">syscall</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 138595 -->
|
|
||||||
64-bit inodes are now supported on FreeBSD 12. Some types have been adjusted accordingly.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 125456 -->
|
|
||||||
The Unix socket
|
|
||||||
(<a href="https://blogs.msdn.microsoft.com/commandline/2017/12/19/af_unix-comes-to-windows/"><code>AF_UNIX</code></a>)
|
|
||||||
address family is now supported for compatible versions of Windows.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 147117 -->
|
|
||||||
The new function <a href="/pkg/syscall/?GOOS=windows&GOARCH=amd64#Syscall18"><code>Syscall18</code></a>
|
|
||||||
has been introduced for Windows, allowing for calls with up to 18 arguments.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</dl><!-- syscall -->
|
|
||||||
|
|
||||||
<dl id="syscall/js"><dt><a href="/pkg/syscall/js/">syscall/js</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 153559 -->
|
|
||||||
<p>
|
|
||||||
The <code>Callback</code> type and <code>NewCallback</code> function have been renamed;
|
|
||||||
they are now called
|
|
||||||
<a href="/pkg/syscall/js/?GOOS=js&GOARCH=wasm#Func"><code>Func</code></a> and
|
|
||||||
<a href="/pkg/syscall/js/?GOOS=js&GOARCH=wasm#FuncOf"><code>FuncOf</code></a>, respectively.
|
|
||||||
This is a breaking change, but WebAssembly support is still experimental
|
|
||||||
and not yet subject to the
|
|
||||||
<a href="/doc/go1compat">Go 1 compatibility promise</a>. Any code using the
|
|
||||||
old names will need to be updated.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 141644 -->
|
|
||||||
If a type implements the new
|
|
||||||
<a href="/pkg/syscall/js/?GOOS=js&GOARCH=wasm#Wrapper"><code>Wrapper</code></a>
|
|
||||||
interface,
|
|
||||||
<a href="/pkg/syscall/js/?GOOS=js&GOARCH=wasm#ValueOf"><code>ValueOf</code></a>
|
|
||||||
will use it to return the JavaScript value for that type.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 143137 -->
|
|
||||||
The meaning of the zero
|
|
||||||
<a href="/pkg/syscall/js/?GOOS=js&GOARCH=wasm#Value"><code>Value</code></a>
|
|
||||||
has changed. It now represents the JavaScript <code>undefined</code> value
|
|
||||||
instead of the number zero.
|
|
||||||
This is a breaking change, but WebAssembly support is still experimental
|
|
||||||
and not yet subject to the
|
|
||||||
<a href="/doc/go1compat">Go 1 compatibility promise</a>. Any code relying on
|
|
||||||
the zero <a href="/pkg/syscall/js/?GOOS=js&GOARCH=wasm#Value"><code>Value</code></a>
|
|
||||||
to mean the number zero will need to be updated.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 144384 -->
|
|
||||||
The new
|
|
||||||
<a href="/pkg/syscall/js/?GOOS=js&GOARCH=wasm#Value.Truthy"><code>Value.Truthy</code></a>
|
|
||||||
method reports the
|
|
||||||
<a href="https://developer.mozilla.org/en-US/docs/Glossary/Truthy">JavaScript "truthiness"</a>
|
|
||||||
of a given value.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</dl><!-- syscall/js -->
|
|
||||||
|
|
||||||
<dl id="testing"><dt><a href="/pkg/testing/">testing</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 139258 -->
|
|
||||||
The <a href="/cmd/go/#hdr-Testing_flags"><code>-benchtime</code></a> flag now supports setting an explicit iteration count instead of a time when the value ends with an "<code>x</code>". For example, <code>-benchtime=100x</code> runs the benchmark 100 times.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</dl><!-- testing -->
|
|
||||||
|
|
||||||
<dl id="text/template"><dt><a href="/pkg/text/template/">text/template</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 142217 -->
|
|
||||||
When executing a template, long context values are no longer truncated in errors.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<code>executing "tmpl" at <.very.deep.context.v...>: map has no entry for key "notpresent"</code>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
is now
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<code>executing "tmpl" at <.very.deep.context.value.notpresent>: map has no entry for key "notpresent"</code>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 143097 -->
|
|
||||||
If a user-defined function called by a template panics, the
|
|
||||||
panic is now caught and returned as an error by
|
|
||||||
the <code>Execute</code> or <code>ExecuteTemplate</code> method.
|
|
||||||
</p>
|
|
||||||
</dl><!-- text/template -->
|
|
||||||
|
|
||||||
<dl id="time"><dt><a href="/pkg/time/">time</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 151299 -->
|
|
||||||
The time zone database in <code>$GOROOT/lib/time/zoneinfo.zip</code>
|
|
||||||
has been updated to version 2018i. Note that this ZIP file is
|
|
||||||
only used if a time zone database is not provided by the operating
|
|
||||||
system.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</dl><!-- time -->
|
|
||||||
|
|
||||||
<dl id="unsafe"><dt><a href="/pkg/unsafe/">unsafe</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 146058 -->
|
|
||||||
It is invalid to convert a nil <code>unsafe.Pointer</code> to <code>uintptr</code> and back with arithmetic.
|
|
||||||
(This was already invalid, but will now cause the compiler to misbehave.)
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</dl><!-- unsafe -->
|
|
1066
doc/go1.13.html
924
doc/go1.14.html
|
@ -1,924 +0,0 @@
|
||||||
<!--{
|
|
||||||
"Title": "Go 1.14 Release Notes",
|
|
||||||
"Path": "/doc/go1.14"
|
|
||||||
}-->
|
|
||||||
|
|
||||||
<!--
|
|
||||||
NOTE: In this document and others in this directory, the convention is to
|
|
||||||
set fixed-width phrases with non-fixed-width spaces, as in
|
|
||||||
<code>hello</code> <code>world</code>.
|
|
||||||
Do not send CLs removing the interior tags from such phrases.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<style>
|
|
||||||
main ul li { margin: 0.5em 0; }
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<h2 id="introduction">Introduction to Go 1.14</h2>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
The latest Go release, version 1.14, arrives six months after <a href="go1.13">Go 1.13</a>.
|
|
||||||
Most of its changes are in the implementation of the toolchain, runtime, and libraries.
|
|
||||||
As always, the release maintains the Go 1 <a href="/doc/go1compat.html">promise of compatibility</a>.
|
|
||||||
We expect almost all Go programs to continue to compile and run as before.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Module support in the <code>go</code> command is now ready for production use,
|
|
||||||
and we encourage all users to <a href="https://blog.golang.org/migrating-to-go-modules">migrate to Go
|
|
||||||
modules for dependency management</a>. If you are unable to migrate due to a problem in the Go
|
|
||||||
toolchain, please ensure that the problem has an
|
|
||||||
<a href="https://golang.org/issue?q=is%3Aissue+is%3Aopen+label%3Amodules">open issue</a>
|
|
||||||
filed. (If the issue is not on the <code>Go1.15</code> milestone, please let us
|
|
||||||
know why it prevents you from migrating so that we can prioritize it
|
|
||||||
appropriately.)
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h2 id="language">Changes to the language</h2>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Per the <a href="https://github.com/golang/proposal/blob/master/design/6977-overlapping-interfaces.md">overlapping interfaces proposal</a>,
|
|
||||||
Go 1.14 now permits embedding of interfaces with overlapping method sets:
|
|
||||||
methods from an embedded interface may have the same names and identical signatures
|
|
||||||
as methods already present in the (embedding) interface. This solves problems that typically
|
|
||||||
(but not exclusively) occur with diamond-shaped embedding graphs.
|
|
||||||
Explicitly declared methods in an interface must remain
|
|
||||||
<a href="https://tip.golang.org/ref/spec#Uniqueness_of_identifiers">unique</a>, as before.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h2 id="ports">Ports</h2>
|
|
||||||
|
|
||||||
<h3 id="darwin">Darwin</h3>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Go 1.14 is the last release that will run on macOS 10.11 El Capitan.
|
|
||||||
Go 1.15 will require macOS 10.12 Sierra or later.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- golang.org/issue/34749 -->
|
|
||||||
Go 1.14 is the last Go release to support 32-bit binaries on
|
|
||||||
macOS (the <code>darwin/386</code> port). They are no longer
|
|
||||||
supported by macOS, starting with macOS 10.15 (Catalina).
|
|
||||||
Go continues to support the 64-bit <code>darwin/amd64</code> port.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- golang.org/issue/34751 -->
|
|
||||||
Go 1.14 will likely be the last Go release to support 32-bit
|
|
||||||
binaries on iOS, iPadOS, watchOS, and tvOS
|
|
||||||
(the <code>darwin/arm</code> port). Go continues to support the
|
|
||||||
64-bit <code>darwin/arm64</code> port.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h3 id="windows">Windows</h3>
|
|
||||||
|
|
||||||
<p><!-- CL 203601 -->
|
|
||||||
Go binaries on Windows now
|
|
||||||
have <a href="https://docs.microsoft.com/en-us/windows/win32/memory/data-execution-prevention">DEP
|
|
||||||
(Data Execution Prevention)</a> enabled.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 202439 -->
|
|
||||||
On Windows, creating a file
|
|
||||||
via <a href="/pkg/os#CreateFile"><code>os.OpenFile</code></a> with
|
|
||||||
the <a href="/pkg/os/#O_CREATE"><code>os.O_CREATE</code></a> flag, or
|
|
||||||
via <a href="/pkg/syscall#Open"><code>syscall.Open</code></a> with
|
|
||||||
the <a href="/pkg/syscall#O_CREAT"><code>syscall.O_CREAT</code></a>
|
|
||||||
flag, will now create the file as read-only if the
|
|
||||||
bit <code>0o200</code> (owner write permission) is not set in the
|
|
||||||
permission argument. This makes the behavior on Windows more like
|
|
||||||
that on Unix systems.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h3 id="wasm">WebAssembly</h3>
|
|
||||||
|
|
||||||
<p><!-- CL 203600 -->
|
|
||||||
JavaScript values referenced from Go via <code>js.Value</code>
|
|
||||||
objects can now be garbage collected.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 203600 -->
|
|
||||||
<code>js.Value</code> values can no longer be compared using
|
|
||||||
the <code>==</code> operator, and instead must be compared using
|
|
||||||
their <code>Equal</code> method.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 203600 -->
|
|
||||||
<code>js.Value</code> now
|
|
||||||
has <code>IsUndefined</code>, <code>IsNull</code>,
|
|
||||||
and <code>IsNaN</code> methods.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h3 id="riscv">RISC-V</h3>
|
|
||||||
|
|
||||||
<p><!-- Issue 27532 -->
|
|
||||||
Go 1.14 contains experimental support for 64-bit RISC-V on Linux
|
|
||||||
(<code>GOOS=linux</code>, <code>GOARCH=riscv64</code>). Be aware
|
|
||||||
that performance, assembly syntax stability, and possibly
|
|
||||||
correctness are a work in progress.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h3 id="freebsd">FreeBSD</h3>
|
|
||||||
|
|
||||||
<p><!-- CL 199919 -->
|
|
||||||
Go now supports the 64-bit ARM architecture on FreeBSD 12.0 or later (the
|
|
||||||
<code>freebsd/arm64</code> port).
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h3 id="nacl">Native Client (NaCl)</h3>
|
|
||||||
|
|
||||||
<p><!-- golang.org/issue/30439 -->
|
|
||||||
As <a href="go1.13#ports">announced</a> in the Go 1.13 release notes,
|
|
||||||
Go 1.14 drops support for the Native Client platform (<code>GOOS=nacl</code>).
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h3 id="illumos">Illumos</h3>
|
|
||||||
|
|
||||||
<p><!-- CL 203758 -->
|
|
||||||
The runtime now respects zone CPU caps
|
|
||||||
(the <code>zone.cpu-cap</code> resource control)
|
|
||||||
for <code>runtime.NumCPU</code> and the default value
|
|
||||||
of <code>GOMAXPROCS</code>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h2 id="tools">Tools</h2>
|
|
||||||
|
|
||||||
<h3 id="go-command">Go command</h3>
|
|
||||||
|
|
||||||
<h4 id="vendor">Vendoring</h4>
|
|
||||||
<!-- golang.org/issue/33848 -->
|
|
||||||
|
|
||||||
<p>
|
|
||||||
When the main module contains a top-level <code>vendor</code> directory and
|
|
||||||
its <code>go.mod</code> file specifies <code>go</code> <code>1.14</code> or
|
|
||||||
higher, the <code>go</code> command now defaults to <code>-mod=vendor</code>
|
|
||||||
for operations that accept that flag. A new value for that flag,
|
|
||||||
<code>-mod=mod</code>, causes the <code>go</code> command to instead load
|
|
||||||
modules from the module cache (as when no <code>vendor</code> directory is
|
|
||||||
present).
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
When <code>-mod=vendor</code> is set (explicitly or by default), the
|
|
||||||
<code>go</code> command now verifies that the main module's
|
|
||||||
<code>vendor/modules.txt</code> file is consistent with its
|
|
||||||
<code>go.mod</code> file.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
<code>go</code> <code>list</code> <code>-m</code> no longer silently omits
|
|
||||||
transitive dependencies that do not provide packages in
|
|
||||||
the <code>vendor</code> directory. It now fails explicitly if
|
|
||||||
<code>-mod=vendor</code> is set and information is requested for a module not
|
|
||||||
mentioned in <code>vendor/modules.txt</code>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h4 id="go-flags">Flags</h4>
|
|
||||||
|
|
||||||
<p><!-- golang.org/issue/32502, golang.org/issue/30345 -->
|
|
||||||
The <code>go</code> <code>get</code> command no longer accepts
|
|
||||||
the <code>-mod</code> flag. Previously, the flag's setting either
|
|
||||||
<a href="https://golang.org/issue/30345">was ignored</a> or
|
|
||||||
<a href="https://golang.org/issue/32502">caused the build to fail</a>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- golang.org/issue/33326 -->
|
|
||||||
<code>-mod=readonly</code> is now set by default when the <code>go.mod</code>
|
|
||||||
file is read-only and no top-level <code>vendor</code> directory is present.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- golang.org/issue/31481 -->
|
|
||||||
<code>-modcacherw</code> is a new flag that instructs the <code>go</code>
|
|
||||||
command to leave newly-created directories in the module cache at their
|
|
||||||
default permissions rather than making them read-only.
|
|
||||||
The use of this flag makes it more likely that tests or other tools will
|
|
||||||
accidentally add files not included in the module's verified checksum.
|
|
||||||
However, it allows the use of <code>rm</code> <code>-rf</code>
|
|
||||||
(instead of <code>go</code> <code>clean</code> <code>-modcache</code>)
|
|
||||||
to remove the module cache.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- golang.org/issue/34506 -->
|
|
||||||
<code>-modfile=file</code> is a new flag that instructs the <code>go</code>
|
|
||||||
command to read (and possibly write) an alternate <code>go.mod</code> file
|
|
||||||
instead of the one in the module root directory. A file
|
|
||||||
named <code>go.mod</code> must still be present in order to determine the
|
|
||||||
module root directory, but it is not accessed. When <code>-modfile</code> is
|
|
||||||
specified, an alternate <code>go.sum</code> file is also used: its path is
|
|
||||||
derived from the <code>-modfile</code> flag by trimming the <code>.mod</code>
|
|
||||||
extension and appending <code>.sum</code>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h4 id="go-env-vars">Environment variables</h4>
|
|
||||||
|
|
||||||
<p><!-- golang.org/issue/32966 -->
|
|
||||||
<code>GOINSECURE</code> is a new environment variable that instructs
|
|
||||||
the <code>go</code> command to not require an HTTPS connection, and to skip
|
|
||||||
certificate validation, when fetching certain modules directly from their
|
|
||||||
origins. Like the existing <code>GOPRIVATE</code> variable, the value
|
|
||||||
of <code>GOINSECURE</code> is a comma-separated list of glob patterns.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h4 id="commands-outside-modules">Commands outside modules</h4>
|
|
||||||
|
|
||||||
<p><!-- golang.org/issue/32027 -->
|
|
||||||
When module-aware mode is enabled explicitly (by setting
|
|
||||||
<code>GO111MODULE=on</code>), most module commands have more
|
|
||||||
limited functionality if no <code>go.mod</code> file is present. For
|
|
||||||
example, <code>go</code> <code>build</code>,
|
|
||||||
<code>go</code> <code>run</code>, and other build commands can only build
|
|
||||||
packages in the standard library and packages specified as <code>.go</code>
|
|
||||||
files on the command line.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Previously, the <code>go</code> command would resolve each package path
|
|
||||||
to the latest version of a module but would not record the module path
|
|
||||||
or version. This resulted in <a href="https://golang.org/issue/32027">slow,
|
|
||||||
non-reproducible builds</a>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
<code>go</code> <code>get</code> continues to work as before, as do
|
|
||||||
<code>go</code> <code>mod</code> <code>download</code> and
|
|
||||||
<code>go</code> <code>list</code> <code>-m</code> with explicit versions.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h4 id="incompatible-versions"><code>+incompatible</code> versions</h4>
|
|
||||||
<!-- golang.org/issue/34165 -->
|
|
||||||
|
|
||||||
<p>
|
|
||||||
If the latest version of a module contains a <code>go.mod</code> file,
|
|
||||||
<code>go</code> <code>get</code> will no longer upgrade to an
|
|
||||||
<a href="/cmd/go/#hdr-Module_compatibility_and_semantic_versioning">incompatible</a>
|
|
||||||
major version of that module unless such a version is requested explicitly
|
|
||||||
or is already required.
|
|
||||||
<code>go</code> <code>list</code> also omits incompatible major versions
|
|
||||||
for such a module when fetching directly from version control, but may
|
|
||||||
include them if reported by a proxy.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
|
|
||||||
<h4 id="go.mod"><code>go.mod</code> file maintenance</h4>
|
|
||||||
<!-- golang.org/issue/34822 -->
|
|
||||||
|
|
||||||
<p>
|
|
||||||
<code>go</code> commands other than
|
|
||||||
<code>go</code> <code>mod</code> <code>tidy</code> no longer
|
|
||||||
remove a <code>require</code> directive that specifies a version of an indirect dependency
|
|
||||||
that is already implied by other (transitive) dependencies of the main
|
|
||||||
module.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
<code>go</code> commands other than
|
|
||||||
<code>go</code> <code>mod</code> <code>tidy</code> no longer
|
|
||||||
edit the <code>go.mod</code> file if the changes are only cosmetic.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
When <code>-mod=readonly</code> is set, <code>go</code> commands will no
|
|
||||||
longer fail due to a missing <code>go</code> directive or an erroneous
|
|
||||||
<code>// indirect</code> comment.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h4 id="module-downloading">Module downloading</h4>
|
|
||||||
|
|
||||||
<p><!-- golang.org/issue/26092 -->
|
|
||||||
The <code>go</code> command now supports Subversion repositories in module mode.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- golang.org/issue/30748 -->
|
|
||||||
The <code>go</code> command now includes snippets of plain-text error messages
|
|
||||||
from module proxies and other HTTP servers.
|
|
||||||
An error message will only be shown if it is valid UTF-8 and consists of only
|
|
||||||
graphic characters and spaces.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h4 id="go-test">Testing</h4>
|
|
||||||
|
|
||||||
<p><!-- golang.org/issue/24929 -->
|
|
||||||
<code>go test -v</code> now streams <code>t.Log</code> output as it happens,
|
|
||||||
rather than at the end of all tests.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h2 id="runtime">Runtime</h2>
|
|
||||||
|
|
||||||
<p><!-- CL 190098 -->
|
|
||||||
This release improves the performance of most uses
|
|
||||||
of <code>defer</code> to incur almost zero overhead compared to
|
|
||||||
calling the deferred function directly.
|
|
||||||
As a result, <code>defer</code> can now be used in
|
|
||||||
performance-critical code without overhead concerns.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 201760, CL 201762 and many others -->
|
|
||||||
Goroutines are now asynchronously preemptible.
|
|
||||||
As a result, loops without function calls no longer potentially
|
|
||||||
deadlock the scheduler or significantly delay garbage collection.
|
|
||||||
This is supported on all platforms except <code>windows/arm</code>,
|
|
||||||
<code>darwin/arm</code>, <code>js/wasm</code>, and
|
|
||||||
<code>plan9/*</code>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
A consequence of the implementation of preemption is that on Unix
|
|
||||||
systems, including Linux and macOS systems, programs built with Go
|
|
||||||
1.14 will receive more signals than programs built with earlier
|
|
||||||
releases.
|
|
||||||
This means that programs that use packages
|
|
||||||
like <a href="/pkg/syscall/"><code>syscall</code></a>
|
|
||||||
or <a href="https://godoc.org/golang.org/x/sys/unix"><code>golang.org/x/sys/unix</code></a>
|
|
||||||
will see more slow system calls fail with <code>EINTR</code> errors.
|
|
||||||
Those programs will have to handle those errors in some way, most
|
|
||||||
likely looping to try the system call again. For more
|
|
||||||
information about this
|
|
||||||
see <a href="http://man7.org/linux/man-pages/man7/signal.7.html"><code>man
|
|
||||||
7 signal</code></a> for Linux systems or similar documentation for
|
|
||||||
other systems.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 201765, CL 195701 and many others -->
|
|
||||||
The page allocator is more efficient and incurs significantly less
|
|
||||||
lock contention at high values of <code>GOMAXPROCS</code>.
|
|
||||||
This is most noticeable as lower latency and higher throughput for
|
|
||||||
large allocations being done in parallel and at a high rate.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 171844 and many others -->
|
|
||||||
Internal timers, used by
|
|
||||||
<a href="/pkg/time/#After"><code>time.After</code></a>,
|
|
||||||
<a href="/pkg/time/#Tick"><code>time.Tick</code></a>,
|
|
||||||
<a href="/pkg/net/#Conn"><code>net.Conn.SetDeadline</code></a>,
|
|
||||||
and friends, are more efficient, with less lock contention and fewer
|
|
||||||
context switches.
|
|
||||||
This is a performance improvement that should not cause any user
|
|
||||||
visible changes.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h2 id="compiler">Compiler</h2>
|
|
||||||
|
|
||||||
<p><!-- CL 162237 -->
|
|
||||||
This release adds <code>-d=checkptr</code> as a compile-time option
|
|
||||||
for adding instrumentation to check that Go code is following
|
|
||||||
<code>unsafe.Pointer</code> safety rules dynamically.
|
|
||||||
This option is enabled by default (except on Windows) with
|
|
||||||
the <code>-race</code> or <code>-msan</code> flags, and can be
|
|
||||||
disabled with <code>-gcflags=all=-d=checkptr=0</code>.
|
|
||||||
Specifically, <code>-d=checkptr</code> checks the following:
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<ol>
|
|
||||||
<li>
|
|
||||||
When converting <code>unsafe.Pointer</code> to <code>*T</code>,
|
|
||||||
the resulting pointer must be aligned appropriately
|
|
||||||
for <code>T</code>.
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
If the result of pointer arithmetic points into a Go heap object,
|
|
||||||
one of the <code>unsafe.Pointer</code>-typed operands must point
|
|
||||||
into the same object.
|
|
||||||
</li>
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Using <code>-d=checkptr</code> is not currently recommended on
|
|
||||||
Windows because it causes false alerts in the standard library.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 204338 -->
|
|
||||||
The compiler can now emit machine-readable logs of key optimizations
|
|
||||||
using the <code>-json</code> flag, including inlining, escape
|
|
||||||
analysis, bounds-check elimination, and nil-check elimination.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 196959 -->
|
|
||||||
Detailed escape analysis diagnostics (<code>-m=2</code>) now work again.
|
|
||||||
This had been dropped from the new escape analysis implementation in
|
|
||||||
the previous release.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 196217 -->
|
|
||||||
All Go symbols in macOS binaries now begin with an underscore,
|
|
||||||
following platform conventions.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 202117 -->
|
|
||||||
This release includes experimental support for compiler-inserted
|
|
||||||
coverage instrumentation for fuzzing.
|
|
||||||
See <a href="https://golang.org/issue/14565">issue 14565</a> for more
|
|
||||||
details.
|
|
||||||
This API may change in future releases.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 174704 --><!-- CL 196784 -->
|
|
||||||
Bounds check elimination now uses information from slice creation and can
|
|
||||||
eliminate checks for indexes with types smaller than <code>int</code>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h2 id="library">Core library</h2>
|
|
||||||
|
|
||||||
<h3 id="hash/maphash">New byte sequence hashing package</h3>
|
|
||||||
|
|
||||||
<p> <!-- golang.org/issue/28322, CL 186877 -->
|
|
||||||
Go 1.14 includes a new package,
|
|
||||||
<a href="/pkg/hash/maphash/"><code>hash/maphash</code></a>,
|
|
||||||
which provides hash functions on byte sequences.
|
|
||||||
These hash functions are intended to be used to implement hash tables or
|
|
||||||
other data structures that need to map arbitrary strings or byte
|
|
||||||
sequences to a uniform distribution on unsigned 64-bit integers.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
The hash functions are collision-resistant but not cryptographically secure.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
The hash value of a given byte sequence is consistent within a
|
|
||||||
single process, but will be different in different processes.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h3 id="minor_library_changes">Minor changes to the library</h3>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
As always, there are various minor changes and updates to the library,
|
|
||||||
made with the Go 1 <a href="/doc/go1compat">promise of compatibility</a>
|
|
||||||
in mind.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<dl id="crypto/tls"><dt><a href="/pkg/crypto/tls/">crypto/tls</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 191976 -->
|
|
||||||
Support for SSL version 3.0 (SSLv3) has been removed. Note that SSLv3 is the
|
|
||||||
<a href="https://tools.ietf.org/html/rfc7568">cryptographically broken</a>
|
|
||||||
protocol predating TLS.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 191999 -->
|
|
||||||
TLS 1.3 can't be disabled via the <code>GODEBUG</code> environment
|
|
||||||
variable anymore. Use the
|
|
||||||
<a href="/pkg/crypto/tls/#Config.MaxVersion"><code>Config.MaxVersion</code></a>
|
|
||||||
field to configure TLS versions.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 205059 -->
|
|
||||||
When multiple certificate chains are provided through the
|
|
||||||
<a href="/pkg/crypto/tls/#Config.Certificates"><code>Config.Certificates</code></a>
|
|
||||||
field, the first one compatible with the peer is now automatically
|
|
||||||
selected. This allows for example providing an ECDSA and an RSA
|
|
||||||
certificate, and letting the package automatically select the best one.
|
|
||||||
Note that the performance of this selection is going to be poor unless the
|
|
||||||
<a href="/pkg/crypto/tls/#Certificate.Leaf"><code>Certificate.Leaf</code></a>
|
|
||||||
field is set. The
|
|
||||||
<a href="/pkg/crypto/tls/#Config.NameToCertificate"><code>Config.NameToCertificate</code></a>
|
|
||||||
field, which only supports associating a single certificate with
|
|
||||||
a give name, is now deprecated and should be left as <code>nil</code>.
|
|
||||||
Similarly the
|
|
||||||
<a href="/pkg/crypto/tls/#Config.BuildNameToCertificate"><code>Config.BuildNameToCertificate</code></a>
|
|
||||||
method, which builds the <code>NameToCertificate</code> field
|
|
||||||
from the leaf certificates, is now deprecated and should not be
|
|
||||||
called.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 175517 -->
|
|
||||||
The new <a href="/pkg/crypto/tls/#CipherSuites"><code>CipherSuites</code></a>
|
|
||||||
and <a href="/pkg/crypto/tls/#InsecureCipherSuites"><code>InsecureCipherSuites</code></a>
|
|
||||||
functions return a list of currently implemented cipher suites.
|
|
||||||
The new <a href="/pkg/crypto/tls/#CipherSuiteName"><code>CipherSuiteName</code></a>
|
|
||||||
function returns a name for a cipher suite ID.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 205058, 205057 -->
|
|
||||||
The new <a href="/pkg/crypto/tls/#ClientHelloInfo.SupportsCertificate">
|
|
||||||
<code>(*ClientHelloInfo).SupportsCertificate</code></a> and
|
|
||||||
<a href="/pkg/crypto/tls/#CertificateRequestInfo.SupportsCertificate">
|
|
||||||
<code>(*CertificateRequestInfo).SupportsCertificate</code></a>
|
|
||||||
methods expose whether a peer supports a certain certificate.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 174329 -->
|
|
||||||
The <code>tls</code> package no longer supports the legacy Next Protocol
|
|
||||||
Negotiation (NPN) extension and now only supports ALPN. In previous
|
|
||||||
releases it supported both. There are no API changes and applications
|
|
||||||
should function identically as before. Most other clients and servers have
|
|
||||||
already removed NPN support in favor of the standardized ALPN.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 205063, 205062 -->
|
|
||||||
RSA-PSS signatures are now used when supported in TLS 1.2 handshakes. This
|
|
||||||
won't affect most applications, but custom
|
|
||||||
<a href="/pkg/crypto/tls/#Certificate.PrivateKey"><code>Certificate.PrivateKey</code></a>
|
|
||||||
implementations that don't support RSA-PSS signatures will need to use the new
|
|
||||||
<a href="/pkg/crypto/tls/#Certificate.SupportedSignatureAlgorithms">
|
|
||||||
<code>Certificate.SupportedSignatureAlgorithms</code></a>
|
|
||||||
field to disable them.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 205059, 205059 -->
|
|
||||||
<a href="/pkg/crypto/tls/#Config.Certificates"><code>Config.Certificates</code></a> and
|
|
||||||
<a href="/pkg/crypto/tls/#Config.GetCertificate"><code>Config.GetCertificate</code></a>
|
|
||||||
can now both be nil if
|
|
||||||
<a href="/pkg/crypto/tls/#Config.GetConfigForClient"><code>Config.GetConfigForClient</code></a>
|
|
||||||
is set. If the callbacks return neither certificates nor an error, the
|
|
||||||
<code>unrecognized_name</code> is now sent.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 205058 -->
|
|
||||||
The new <a href="/pkg/crypto/tls/#CertificateRequestInfo.Version"><code>CertificateRequestInfo.Version</code></a>
|
|
||||||
field provides the TLS version to client certificates callbacks.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 205068 -->
|
|
||||||
The new <code>TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256</code> and
|
|
||||||
<code>TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256</code> constants use
|
|
||||||
the final names for the cipher suites previously referred to as
|
|
||||||
<code>TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305</code> and
|
|
||||||
<code>TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305</code>.
|
|
||||||
</p>
|
|
||||||
</dd>
|
|
||||||
</dl><!-- crypto/tls -->
|
|
||||||
|
|
||||||
<dl id="crypto/x509"><dt><a href="/pkg/crypto/x509/">crypto/x509</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 204046 -->
|
|
||||||
<a href="/pkg/crypto/x509/#Certificate.CreateCRL"><code>Certificate.CreateCRL</code></a>
|
|
||||||
now supports Ed25519 issuers.
|
|
||||||
</p>
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
|
|
||||||
<dl id="debug/dwarf"><dt><a href="/pkg/debug/dwarf/">debug/dwarf</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 175138 -->
|
|
||||||
The <code>debug/dwarf</code> package now supports reading DWARF
|
|
||||||
version 5.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
The new
|
|
||||||
method <a href="/pkg/debug/dwarf/#Data.AddSection"><code>(*Data).AddSection</code></a>
|
|
||||||
supports adding arbitrary new DWARF sections from the input file
|
|
||||||
to the DWARF <code>Data</code>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 192698 -->
|
|
||||||
The new
|
|
||||||
method <a href="/pkg/debug/dwarf/#Reader.ByteOrder"><code>(*Reader).ByteOrder</code></a>
|
|
||||||
returns the byte order of the current compilation unit.
|
|
||||||
This may be used to interpret attributes that are encoded in the
|
|
||||||
native ordering, such as location descriptions.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 192699 -->
|
|
||||||
The new
|
|
||||||
method <a href="/pkg/debug/dwarf/#LineReader.Files"><code>(*LineReader).Files</code></a>
|
|
||||||
returns the file name table from a line reader.
|
|
||||||
This may be used to interpret the value of DWARF attributes such
|
|
||||||
as <code>AttrDeclFile</code>.
|
|
||||||
</p>
|
|
||||||
</dd>
|
|
||||||
</dl><!-- debug/dwarf -->
|
|
||||||
|
|
||||||
<dl id="encoding/asn1"><dt><a href="/pkg/encoding/asn1/">encoding/asn1</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 126624 -->
|
|
||||||
<a href="/pkg/encoding/asn1/#Unmarshal"><code>Unmarshal</code></a>
|
|
||||||
now supports ASN.1 string type BMPString, represented by the new
|
|
||||||
<a href="/pkg/encoding/asn1/#TagBMPString"><code>TagBMPString</code></a>
|
|
||||||
constant.
|
|
||||||
</p>
|
|
||||||
</dd>
|
|
||||||
</dl><!-- encoding/asn1 -->
|
|
||||||
|
|
||||||
<dl id="encoding/json"><dt><a href="/pkg/encoding/json/">encoding/json</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 200677 -->
|
|
||||||
The <a href="/pkg/encoding/json/#Decoder"><code>Decoder</code></a>
|
|
||||||
type supports a new
|
|
||||||
method <a href="/pkg/encoding/json/#Decoder.InputOffset"><code>InputOffset</code></a>
|
|
||||||
that returns the input stream byte offset of the current
|
|
||||||
decoder position.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 200217 -->
|
|
||||||
<a href="/pkg/encoding/json/#Compact"><code>Compact</code></a> no longer
|
|
||||||
escapes the <code>U+2028</code> and <code>U+2029</code> characters, which
|
|
||||||
was never a documented feature. For proper escaping, see <a
|
|
||||||
href="/pkg/encoding/json/#HTMLEscape"><code>HTMLEscape</code></a>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 195045 -->
|
|
||||||
<a href="/pkg/encoding/json/#Number"><code>Number</code></a> no longer
|
|
||||||
accepts invalid numbers, to follow the documented behavior more closely.
|
|
||||||
If a program needs to accept invalid numbers like the empty string,
|
|
||||||
consider wrapping the type with <a href="/pkg/encoding/json/#Unmarshaler"><code>Unmarshaler</code></a>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 200237 -->
|
|
||||||
<a href="/pkg/encoding/json/#Unmarshal"><code>Unmarshal</code></a>
|
|
||||||
can now support map keys with string underlying type which implement
|
|
||||||
<a href="/pkg/encoding/#TextUnmarshaler"><code>encoding.TextUnmarshaler</code></a>.
|
|
||||||
</p>
|
|
||||||
</dd>
|
|
||||||
</dl><!-- encoding/json -->
|
|
||||||
|
|
||||||
<dl id="go/build"><dt><a href="/pkg/go/build/">go/build</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 203820, 211657 -->
|
|
||||||
The <a href="/pkg/go/build/#Context"><code>Context</code></a>
|
|
||||||
type has a new field <code>Dir</code> which may be used to set
|
|
||||||
the working directory for the build.
|
|
||||||
The default is the current directory of the running process.
|
|
||||||
In module mode, this is used to locate the main module.
|
|
||||||
</p>
|
|
||||||
</dd>
|
|
||||||
</dl><!-- go/build -->
|
|
||||||
|
|
||||||
<dl id="go/doc"><dt><a href="/pkg/go/doc/">go/doc</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 204830 -->
|
|
||||||
The new
|
|
||||||
function <a href="/pkg/go/doc/#NewFromFiles"><code>NewFromFiles</code></a>
|
|
||||||
computes package documentation from a list
|
|
||||||
of <code>*ast.File</code>'s and associates examples with the
|
|
||||||
appropriate package elements.
|
|
||||||
The new information is available in a new <code>Examples</code>
|
|
||||||
field
|
|
||||||
in the <a href="/pkg/go/doc/#Package"><code>Package</code></a>, <a href="/pkg/go/doc/#Type"><code>Type</code></a>,
|
|
||||||
and <a href="/pkg/go/doc/#Func"><code>Func</code></a> types, and a
|
|
||||||
new <a href="/pkg/go/doc/#Example.Suffix"><code>Suffix</code></a>
|
|
||||||
field in
|
|
||||||
the <a href="/pkg/go/doc/#Example"><code>Example</code></a>
|
|
||||||
type.
|
|
||||||
</p>
|
|
||||||
</dd>
|
|
||||||
</dl><!-- go/doc -->
|
|
||||||
|
|
||||||
<dl id="io/ioutil"><dt><a href="/pkg/io/ioutil/">io/ioutil</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 198488 -->
|
|
||||||
<a href="/pkg/io/ioutil/#TempDir"><code>TempDir</code></a> can now create directories
|
|
||||||
whose names have predictable prefixes and suffixes.
|
|
||||||
As with <a href="/pkg/io/ioutil/#TempFile"><code>TempFile</code></a>, if the pattern
|
|
||||||
contains a '*', the random string replaces the last '*'.
|
|
||||||
</p>
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
|
|
||||||
<dl id="log"><dt><a href="/pkg/log/">log</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 186182 -->
|
|
||||||
The
|
|
||||||
new <a href="https://tip.golang.org/pkg/log/#pkg-constants"><code>Lmsgprefix</code></a>
|
|
||||||
flag may be used to tell the logging functions to emit the
|
|
||||||
optional output prefix immediately before the log message rather
|
|
||||||
than at the start of the line.
|
|
||||||
</p>
|
|
||||||
</dd>
|
|
||||||
</dl><!-- log -->
|
|
||||||
|
|
||||||
<dl id="math"><dt><a href="/pkg/math/">math</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 127458 -->
|
|
||||||
The new <a href="/pkg/math/#FMA"><code>FMA</code></a> function
|
|
||||||
computes <code>x*y+z</code> in floating point with no
|
|
||||||
intermediate rounding of the <code>x*y</code>
|
|
||||||
computation. Several architectures implement this computation
|
|
||||||
using dedicated hardware instructions for additional performance.
|
|
||||||
</p>
|
|
||||||
</dd>
|
|
||||||
</dl><!-- math -->
|
|
||||||
|
|
||||||
<dl id="math/big"><dt><a href="/pkg/math/big/">math/big</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 164972 -->
|
|
||||||
The <a href="/pkg/math/big/#Int.GCD"><code>GCD</code></a> method
|
|
||||||
now allows the inputs <code>a</code> and <code>b</code> to be
|
|
||||||
zero or negative.
|
|
||||||
</p>
|
|
||||||
</dd>
|
|
||||||
</dl><!-- math/big -->
|
|
||||||
|
|
||||||
<dl id="math/bits"><dt><a href="/pkg/math/bits/">math/bits</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 197838 -->
|
|
||||||
The new functions
|
|
||||||
<a href="/pkg/math/bits/#Rem"><code>Rem</code></a>,
|
|
||||||
<a href="/pkg/math/bits/#Rem32"><code>Rem32</code></a>, and
|
|
||||||
<a href="/pkg/math/bits/#Rem64"><code>Rem64</code></a>
|
|
||||||
support computing a remainder even when the quotient overflows.
|
|
||||||
</p>
|
|
||||||
</dd>
|
|
||||||
</dl><!-- math/bits -->
|
|
||||||
|
|
||||||
<dl id="mime"><dt><a href="/pkg/mime/">mime</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 186927 -->
|
|
||||||
The default type of <code>.js</code> and <code>.mjs</code> files
|
|
||||||
is now <code>text/javascript</code> rather
|
|
||||||
than <code>application/javascript</code>.
|
|
||||||
This is in accordance
|
|
||||||
with <a href="https://datatracker.ietf.org/doc/draft-ietf-dispatch-javascript-mjs/">an
|
|
||||||
IETF draft</a> that treats <code>application/javascript</code> as obsolete.
|
|
||||||
</p>
|
|
||||||
</dd>
|
|
||||||
</dl><!-- mime -->
|
|
||||||
|
|
||||||
<dl id="mime/multipart"><dt><a href="/pkg/mime/multipart/">mime/multipart</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p>
|
|
||||||
The
|
|
||||||
new <a href="/pkg/mime/multipart/#Reader"><code>Reader</code></a>
|
|
||||||
method <a href="/pkg/mime/multipart/#Reader.NextRawPart"><code>NextRawPart</code></a>
|
|
||||||
supports fetching the next MIME part without transparently
|
|
||||||
decoding <code>quoted-printable</code> data.
|
|
||||||
</p>
|
|
||||||
</dd>
|
|
||||||
</dl><!-- mime/multipart -->
|
|
||||||
|
|
||||||
<dl id="net/http"><dt><a href="/pkg/net/http/">net/http</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 200760 -->
|
|
||||||
The new <a href="/pkg/net/http/#Header"><code>Header</code></a>
|
|
||||||
method <a href="/pkg/net/http/#Header.Values"><code>Values</code></a>
|
|
||||||
can be used to fetch all values associated with a
|
|
||||||
canonicalized key.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 61291 -->
|
|
||||||
The
|
|
||||||
new <a href="/pkg/net/http/#Transport"><code>Transport</code></a>
|
|
||||||
field <a href="/pkg/net/http/#Transport.DialTLSContext"><code>DialTLSContext</code></a>
|
|
||||||
can be used to specify an optional dial function for creating
|
|
||||||
TLS connections for non-proxied HTTPS requests.
|
|
||||||
This new field can be used instead
|
|
||||||
of <a href="/pkg/net/http/#Transport.DialTLS"><code>DialTLS</code></a>,
|
|
||||||
which is now considered deprecated; <code>DialTLS</code> will
|
|
||||||
continue to work, but new code should
|
|
||||||
use <code>DialTLSContext</code>, which allows the transport to
|
|
||||||
cancel dials as soon as they are no longer needed.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 192518, CL 194218 -->
|
|
||||||
On Windows, <a href="/pkg/net/http/#ServeFile"><code>ServeFile</code></a> now correctly
|
|
||||||
serves files larger than 2GB.
|
|
||||||
</p>
|
|
||||||
</dd>
|
|
||||||
</dl><!-- net/http -->
|
|
||||||
|
|
||||||
<dl id="net/http/httptest"><dt><a href="/pkg/net/http/httptest/">net/http/httptest</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 201557 -->
|
|
||||||
The
|
|
||||||
new <a href="/pkg/net/http/httptest/#Server"><code>Server</code></a>
|
|
||||||
field <a href="/pkg/net/http/httptest/#Server.EnableHTTP2"><code>EnableHTTP2</code></a>
|
|
||||||
supports enabling HTTP/2 on the test server.
|
|
||||||
</p>
|
|
||||||
</dd>
|
|
||||||
</dl><!-- net/http/httptest -->
|
|
||||||
|
|
||||||
<dl id="net/textproto"><dt><a href="/pkg/net/textproto/">net/textproto</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 200760 -->
|
|
||||||
The
|
|
||||||
new <a href="/pkg/net/textproto/#MIMEHeader"><code>MIMEHeader</code></a>
|
|
||||||
method <a href="/pkg/net/textproto/#MIMEHeader.Values"><code>Values</code></a>
|
|
||||||
can be used to fetch all values associated with a canonicalized
|
|
||||||
key.
|
|
||||||
</p>
|
|
||||||
</dd>
|
|
||||||
</dl><!-- net/textproto -->
|
|
||||||
|
|
||||||
<dl id="net/url"><dt><a href="/pkg/net/url/">net/url</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 185117 -->
|
|
||||||
When parsing of a URL fails
|
|
||||||
(for example by <a href="/pkg/net/url/#Parse"><code>Parse</code></a>
|
|
||||||
or <a href="/pkg/net/url/#ParseRequestURI"><code>ParseRequestURI</code></a>),
|
|
||||||
the resulting <a href="/pkg/net/url/#Error.Error"><code>Error</code></a> message
|
|
||||||
will now quote the unparsable URL.
|
|
||||||
This provides clearer structure and consistency with other parsing errors.
|
|
||||||
</p>
|
|
||||||
</dd>
|
|
||||||
</dl><!-- net/url -->
|
|
||||||
|
|
||||||
<dl id="os/signal"><dt><a href="/pkg/os/signal/">os/signal</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 187739 -->
|
|
||||||
On Windows,
|
|
||||||
the <code>CTRL_CLOSE_EVENT</code>, <code>CTRL_LOGOFF_EVENT</code>,
|
|
||||||
and <code>CTRL_SHUTDOWN_EVENT</code> events now generate
|
|
||||||
a <code>syscall.SIGTERM</code> signal, similar to how Control-C
|
|
||||||
and Control-Break generate a <code>syscall.SIGINT</code> signal.
|
|
||||||
</p>
|
|
||||||
</dd>
|
|
||||||
</dl><!-- os/signal -->
|
|
||||||
|
|
||||||
<dl id="plugin"><dt><a href="/pkg/plugin/">plugin</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 191617 -->
|
|
||||||
The <code>plugin</code> package now supports <code>freebsd/amd64</code>.
|
|
||||||
</p>
|
|
||||||
</dd>
|
|
||||||
</dl><!-- plugin -->
|
|
||||||
|
|
||||||
<dl id="reflect"><dt><a href="/pkg/reflect/">reflect</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 85661 -->
|
|
||||||
<a href="/pkg/reflect#StructOf"><code>StructOf</code></a> now
|
|
||||||
supports creating struct types with unexported fields, by
|
|
||||||
setting the <code>PkgPath</code> field in
|
|
||||||
a <code>StructField</code> element.
|
|
||||||
</p>
|
|
||||||
</dd>
|
|
||||||
</dl><!-- reflect -->
|
|
||||||
|
|
||||||
<dl id="pkg-runtime"><dt><a href="/pkg/runtime/">runtime</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 200081 -->
|
|
||||||
<code>runtime.Goexit</code> can no longer be aborted by a
|
|
||||||
recursive <code>panic</code>/<code>recover</code>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><!-- CL 188297, CL 191785 -->
|
|
||||||
On macOS, <code>SIGPIPE</code> is no longer forwarded to signal
|
|
||||||
handlers installed before the Go runtime is initialized.
|
|
||||||
This is necessary because macOS delivers <code>SIGPIPE</code>
|
|
||||||
<a href="https://golang.org/issue/33384">to the main thread</a>
|
|
||||||
rather than the thread writing to the closed pipe.
|
|
||||||
</p>
|
|
||||||
</dd>
|
|
||||||
</dl><!-- runtime -->
|
|
||||||
|
|
||||||
<dl id="runtime/pprof"><dt><a href="/pkg/runtime/pprof/">runtime/pprof</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 204636, 205097 -->
|
|
||||||
The generated profile no longer includes the pseudo-PCs used for inline
|
|
||||||
marks. Symbol information of inlined functions is encoded in
|
|
||||||
<a href="https://github.com/google/pprof/blob/5e96527/proto/profile.proto#L177-L184">the format</a>
|
|
||||||
the pprof tool expects. This is a fix for the regression introduced
|
|
||||||
during recent releases.
|
|
||||||
</p>
|
|
||||||
</dd>
|
|
||||||
</dl><!-- runtime/pprof -->
|
|
||||||
|
|
||||||
<dl id="strconv"><dt><a href="/pkg/strconv/">strconv</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p>
|
|
||||||
The <a href="/pkg/strconv/#NumError"><code>NumError</code></a>
|
|
||||||
type now has
|
|
||||||
an <a href="/pkg/strconv/#NumError.Unwrap"><code>Unwrap</code></a>
|
|
||||||
method that may be used to retrieve the reason that a conversion
|
|
||||||
failed.
|
|
||||||
This supports using <code>NumError</code> values
|
|
||||||
with <a href="/pkg/errors/#Is"><code>errors.Is</code></a> to see
|
|
||||||
if the underlying error
|
|
||||||
is <a href="/pkg/strconv/#pkg-variables"><code>strconv.ErrRange</code></a>
|
|
||||||
or <a href="/pkg/strconv/#pkg-variables"><code>strconv.ErrSyntax</code></a>.
|
|
||||||
</p>
|
|
||||||
</dd>
|
|
||||||
</dl><!-- strconv -->
|
|
||||||
|
|
||||||
<dl id="sync"><dt><a href="/pkg/sync/">sync</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 200577 -->
|
|
||||||
Unlocking a highly contended <code>Mutex</code> now directly
|
|
||||||
yields the CPU to the next goroutine waiting for
|
|
||||||
that <code>Mutex</code>. This significantly improves the
|
|
||||||
performance of highly contended mutexes on high CPU count
|
|
||||||
machines.
|
|
||||||
</p>
|
|
||||||
</dd>
|
|
||||||
</dl><!-- sync -->
|
|
||||||
|
|
||||||
<dl id="testing"><dt><a href="/pkg/testing/">testing</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 201359 -->
|
|
||||||
The testing package now supports cleanup functions, called after
|
|
||||||
a test or benchmark has finished, by calling
|
|
||||||
<a href="/pkg/testing#T.Cleanup"><code>T.Cleanup</code></a> or
|
|
||||||
<a href="/pkg/testing#B.Cleanup"><code>B.Cleanup</code></a> respectively.
|
|
||||||
</p>
|
|
||||||
</dd>
|
|
||||||
</dl><!-- testing -->
|
|
||||||
|
|
||||||
<dl id="text/template"><dt><a href="/pkg/text/template/">text/template</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p><!-- CL 206124 -->
|
|
||||||
The text/template package now correctly reports errors when a
|
|
||||||
parenthesized argument is used as a function.
|
|
||||||
This most commonly shows up in erroneous cases like
|
|
||||||
<code>{{if (eq .F "a") or (eq .F "b")}}</code>.
|
|
||||||
This should be written as <code>{{if or (eq .F "a") (eq .F "b")}}</code>.
|
|
||||||
The erroneous case never worked as expected, and will now be
|
|
||||||
reported with an error <code>can't give argument to non-function</code>.
|
|
||||||
</p>
|
|
||||||
</dd>
|
|
||||||
</dl><!-- text/template -->
|
|
||||||
|
|
||||||
<dl id="unicode"><dt><a href="/pkg/unicode/">unicode</a></dt>
|
|
||||||
<dd>
|
|
||||||
<p>
|
|
||||||
The <a href="/pkg/unicode/"><code>unicode</code></a> package and associated
|
|
||||||
support throughout the system has been upgraded from Unicode 11.0 to
|
|
||||||
<a href="https://www.unicode.org/versions/Unicode12.0.0/">Unicode 12.0</a>,
|
|
||||||
which adds 554 new characters, including four new scripts, and 61 new emoji.
|
|
||||||
</p>
|
|
||||||
</dd>
|
|
||||||
</dl><!-- unicode -->
|
|
1064
doc/go1.15.html
|
@ -14,13 +14,13 @@ Do not send CLs removing the interior tags from such phrases.
|
||||||
main ul li { margin: 0.5em 0; }
|
main ul li { margin: 0.5em 0; }
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<h2 id="introduction">DRAFT RELEASE NOTES — Introduction to Go 1.16</h2>
|
<h2 id="introduction">Introduction to Go 1.16</h2>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<strong>
|
The latest Go release, version 1.16, arrives six months after <a href="/doc/go1.15">Go 1.15</a>.
|
||||||
Go 1.16 is not yet released. These are work-in-progress
|
Most of its changes are in the implementation of the toolchain, runtime, and libraries.
|
||||||
release notes. Go 1.16 is expected to be released in February 2021.
|
As always, the release maintains the Go 1 <a href="/doc/go1compat.html">promise of compatibility</a>.
|
||||||
</strong>
|
We expect almost all Go programs to continue to compile and run as before.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2 id="language">Changes to the language</h2>
|
<h2 id="language">Changes to the language</h2>
|
||||||
|
@ -174,10 +174,12 @@ Do not send CLs removing the interior tags from such phrases.
|
||||||
non-reproducible builds.
|
non-reproducible builds.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p><!-- golang.org/issue/43052 -->
|
<p><!-- golang.org/issue/43052, golang.org/issue/43985 -->
|
||||||
The <code>go</code> command now disallows non-ASCII import paths in module
|
In module mode, the <code>go</code> command now disallows import paths that
|
||||||
mode. Non-ASCII module paths have already been disallowed so this change
|
include non-ASCII characters or path elements with a leading dot character
|
||||||
affects module subdirectory paths that contain non-ASCII characters.
|
(<code>.</code>). Module paths with these characters were already disallowed
|
||||||
|
(see <a href="/ref/mod#go-mod-file-ident">Module paths and versions</a>),
|
||||||
|
so this change affects only paths within module subdirectories.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h4 id="embed">Embedding Files</h4>
|
<h4 id="embed">Embedding Files</h4>
|
||||||
|
@ -315,7 +317,7 @@ Do not send CLs removing the interior tags from such phrases.
|
||||||
|
|
||||||
<h3 id="vet">Vet</h3>
|
<h3 id="vet">Vet</h3>
|
||||||
|
|
||||||
<h4 id="vet-string-int">New warning for invalid testing.T use in
|
<h4 id="vet-testing-T">New warning for invalid testing.T use in
|
||||||
goroutines</h4>
|
goroutines</h4>
|
||||||
|
|
||||||
<p><!-- CL 235677 -->
|
<p><!-- CL 235677 -->
|
||||||
|
@ -378,6 +380,16 @@ func TestFoo(t *testing.T) {
|
||||||
fixes.
|
fixes.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<h4 id="vet-asn1-unmarshal">New warning for asn1.Unmarshal</h4>
|
||||||
|
|
||||||
|
<p><!-- CL 243397 -->
|
||||||
|
The vet tool now warns about incorrectly passing a non-pointer or nil argument to
|
||||||
|
<a href="/pkg/encoding/asn1/#Unmarshal"><code>asn1.Unmarshal</code></a>.
|
||||||
|
This is like the existing checks for
|
||||||
|
<a href="/pkg/encoding/json/#Unmarshal"><code>encoding/json.Unmarshal</code></a>
|
||||||
|
and <a href="/pkg/encoding/xml/#Unmarshal"><code>encoding/xml.Unmarshal</code></a>.
|
||||||
|
</p>
|
||||||
|
|
||||||
<h2 id="runtime">Runtime</h2>
|
<h2 id="runtime">Runtime</h2>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
@ -493,7 +505,7 @@ func TestFoo(t *testing.T) {
|
||||||
On the consumer side,
|
On the consumer side,
|
||||||
the new <a href="/pkg/net/http/#FS"><code>http.FS</code></a>
|
the new <a href="/pkg/net/http/#FS"><code>http.FS</code></a>
|
||||||
function converts an <code>fs.FS</code> to an
|
function converts an <code>fs.FS</code> to an
|
||||||
<a href="/pkg/net/http/#Handler"><code>http.Handler</code></a>.
|
<a href="/pkg/net/http/#FileSystem"><code>http.FileSystem</code></a>.
|
||||||
Also, the <a href="/pkg/html/template/"><code>html/template</code></a>
|
Also, the <a href="/pkg/html/template/"><code>html/template</code></a>
|
||||||
and <a href="/pkg/text/template/"><code>text/template</code></a>
|
and <a href="/pkg/text/template/"><code>text/template</code></a>
|
||||||
packages’ <a href="/pkg/html/template/#ParseFS"><code>ParseFS</code></a>
|
packages’ <a href="/pkg/html/template/#ParseFS"><code>ParseFS</code></a>
|
||||||
|
@ -940,7 +952,7 @@ func TestFoo(t *testing.T) {
|
||||||
<p><!-- CL 243939 -->
|
<p><!-- CL 243939 -->
|
||||||
The new <a href="/pkg/net/http/#FS"><code>http.FS</code></a>
|
The new <a href="/pkg/net/http/#FS"><code>http.FS</code></a>
|
||||||
function converts an <a href="/pkg/io/fs/#FS"><code>fs.FS</code></a>
|
function converts an <a href="/pkg/io/fs/#FS"><code>fs.FS</code></a>
|
||||||
to an <a href="/pkg/net/http/#Handler"><code>http.Handler</code></a>.
|
to an <a href="/pkg/net/http/#FileSystem"><code>http.FileSystem</code></a>.
|
||||||
</p>
|
</p>
|
||||||
</dd>
|
</dd>
|
||||||
</dl><!-- net/http -->
|
</dl><!-- net/http -->
|
||||||
|
|
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
|
|
||||||
toolchain 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="https://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="https://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 toolchain 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 toolchain, 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/golang.org/x/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/golang.org/x/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="https://9p.io/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>multipart/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>
|
|
896
doc/go1.4.html
|
@ -1,896 +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.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
It contains only one tiny language change,
|
|
||||||
in the form of a backwards-compatible simple variant of <code>for</code>-<code>range</code> loop,
|
|
||||||
and a possibly breaking change to the compiler involving methods on pointers-to-pointers.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
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 for AMD64 on Plan 9.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
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 i, v := range x {
|
|
||||||
...
|
|
||||||
}
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
and
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
for i := 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="https://golang.org/x/mobile">mobile</a> subrepository.
|
|
||||||
A brief description of the plans for this experimental port are available
|
|
||||||
<a href="https://golang.org/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>
|
|
||||||
Prior 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="https://golang.org/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 from 8192 bytes to 2048 bytes.
|
|
||||||
</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="https://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="https://golang.org/s/go14customimport">the design document</a>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h3 id="subrepo">Import paths for the subrepositories</h3>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
The Go project subrepositories (<code>code.google.com/p/go.tools</code> and so on)
|
|
||||||
are now available under custom import paths replacing <code>code.google.com/p/go.</code> with <code>golang.org/x/</code>,
|
|
||||||
as in <code>golang.org/x/tools</code>.
|
|
||||||
We will add canonical import comments to the code around June 1, 2015,
|
|
||||||
at which point Go 1.4 and later will stop accepting the old <code>code.google.com</code> paths.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
<em>Updating</em>: All code that imports from subrepositories should change
|
|
||||||
to use the new <code>golang.org</code> paths.
|
|
||||||
Go 1.0 and later can resolve and import the new paths, so updating will not break
|
|
||||||
compatibility with older releases.
|
|
||||||
Code that has not updated will stop compiling with Go 1.4 around June 1, 2015.
|
|
||||||
</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="https://godoc.org/golang.org/x/tools/cmd/stringer">stringer</a>
|
|
||||||
tool in the <code>golang.org/x/tools</code> subrepository.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
For more information, see the
|
|
||||||
<a href="https://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 subrepositories.
|
|
||||||
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 runtime changes in this release, Go 1.4 requires SWIG 3.0.3.
|
|
||||||
</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="//golang.org/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="https://golang.org/s/go1.4-syscall">a
|
|
||||||
separate document</a>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
A new subrepository, <a href="https://golang.org/x/sys">golang.org/x/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="https://godoc.org/golang.org/x/sys/unix">Unix</a>,
|
|
||||||
<a href="https://godoc.org/golang.org/x/sys/windows">Windows</a> and
|
|
||||||
<a href="https://godoc.org/golang.org/x/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>golang.org/x/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/archive/zip/"><code>archive/zip</code></a> package's
|
|
||||||
<a href="/pkg/archive/zip/#Writer"><code>Writer</code></a> now supports a
|
|
||||||
<a href="/pkg/archive/zip/#Writer.Flush"><code>Flush</code></a> method.
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<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.
|
|
||||||
The <a href="/pkg/compress/gzip/"><code>compress/gzip</code></a> package also has a
|
|
||||||
<a href="/pkg/compress/gzip/#Reader.Multistream"><code>Multistream</code></a> method to control support
|
|
||||||
for multistream files.
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
The <a href="/pkg/crypto/"><code>crypto</code></a> package now has a
|
|
||||||
<a href="/pkg/crypto/#Signer"><code>Signer</code></a> interface, implemented by the
|
|
||||||
<code>PrivateKey</code> types in
|
|
||||||
<a href="/pkg/crypto/ecdsa"><code>crypto/ecdsa</code></a> and
|
|
||||||
<a href="/pkg/crypto/rsa"><code>crypto/rsa</code></a>.
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
The <a href="/pkg/crypto/tls/"><code>crypto/tls</code></a> package
|
|
||||||
now supports ALPN as defined in <a href="https://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/crypto/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>
|
|
||||||
The <a href="/pkg/database/sql/"><code>database/sql</code></a> package can now list all registered
|
|
||||||
<a href="/pkg/database/sql/#Drivers"><code>Drivers</code></a>.
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
The <a href="/pkg/debug/dwarf/"><code>debug/dwarf</code></a> package now supports
|
|
||||||
<a href="/pkg/debug/dwarf/#UnspecifiedType"><code>UnspecifiedType</code></a>s.
|
|
||||||
</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>
|
|
||||||
The <a href="/pkg/encoding/xml/"><code>encoding/xml</code></a> package's
|
|
||||||
<a href="/pkg/encoding/xml/#Decoder"><code>Decoder</code></a> can now report its input offset.
|
|
||||||
</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/image/"><code>image</code></a> package's
|
|
||||||
<a href="/pkg/image/#Image"><code>Image</code></a>
|
|
||||||
implementations like
|
|
||||||
<a href="/pkg/image/#RGBA"><code>RGBA</code></a> and
|
|
||||||
<a href="/pkg/image/#Gray"><code>Gray</code></a> have specialized
|
|
||||||
<a href="/pkg/image/#RGBA.RGBAAt"><code>RGBAAt</code></a> and
|
|
||||||
<a href="/pkg/image/#Gray.GrayAt"><code>GrayAt</code></a> methods alongside the general
|
|
||||||
<a href="/pkg/image/#Image.At"><code>At</code></a> method.
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
The <a href="/pkg/image/png/"><code>image/png</code></a> package now has an
|
|
||||||
<a href="/pkg/image/png/#Encoder"><code>Encoder</code></a>
|
|
||||||
type to control the compression level used for encoding.
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
The <a href="/pkg/math/"><code>math</code></a> package now has a
|
|
||||||
<a href="/pkg/math/#Nextafter32"><code>Nextafter32</code><a/> function.
|
|
||||||
</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.
|
|
||||||
There is also a new <a href="/pkg/os/#Unsetenv"><code>Unsetenv</code></a> function.
|
|
||||||
</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>
|
|
1310
doc/go1.5.html
923
doc/go1.6.html
|
@ -1,923 +0,0 @@
|
||||||
<!--{
|
|
||||||
"Title": "Go 1.6 Release Notes",
|
|
||||||
"Path": "/doc/go1.6",
|
|
||||||
"Template": true
|
|
||||||
}-->
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Edit .,s;^PKG:([a-z][A-Za-z0-9_/]+);<a href="/pkg/\1/"><code>\1</code></a>;g
|
|
||||||
Edit .,s;^([a-z][A-Za-z0-9_/]+)\.([A-Z][A-Za-z0-9_]+\.)?([A-Z][A-Za-z0-9_]+)([ .',]|$);<a href="/pkg/\1/#\2\3"><code>\3</code></a>\4;g
|
|
||||||
-->
|
|
||||||
|
|
||||||
<style>
|
|
||||||
main ul li { margin: 0.5em 0; }
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<h2 id="introduction">Introduction to Go 1.6</h2>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
The latest Go release, version 1.6, arrives six months after 1.5.
|
|
||||||
Most of its changes are in the implementation of the language, runtime, and libraries.
|
|
||||||
There are no changes to the language specification.
|
|
||||||
As always, the release maintains the Go 1 <a href="/doc/go1compat.html">promise of compatibility</a>.
|
|
||||||
We expect almost all Go programs to continue to compile and run as before.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
The release adds new ports to <a href="#ports">Linux on 64-bit MIPS and Android on 32-bit x86</a>;
|
|
||||||
defined and enforced <a href="#cgo">rules for sharing Go pointers with C</a>;
|
|
||||||
transparent, automatic <a href="#http2">support for HTTP/2</a>;
|
|
||||||
and a new mechanism for <a href="#template">template reuse</a>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h2 id="language">Changes to the language</h2>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
There are no language changes in this release.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h2 id="ports">Ports</h2>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Go 1.6 adds experimental ports to
|
|
||||||
Linux on 64-bit MIPS (<code>linux/mips64</code> and <code>linux/mips64le</code>).
|
|
||||||
These ports support <code>cgo</code> but only with internal linking.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Go 1.6 also adds an experimental port to Android on 32-bit x86 (<code>android/386</code>).
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
On FreeBSD, Go 1.6 defaults to using <code>clang</code>, not <code>gcc</code>, as the external C compiler.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
On Linux on little-endian 64-bit PowerPC (<code>linux/ppc64le</code>),
|
|
||||||
Go 1.6 now supports <code>cgo</code> with external linking and
|
|
||||||
is roughly feature complete.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
On NaCl, Go 1.5 required SDK version pepper-41.
|
|
||||||
Go 1.6 adds support for later SDK versions.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
On 32-bit x86 systems using the <code>-dynlink</code> or <code>-shared</code> compilation modes,
|
|
||||||
the register CX is now overwritten by certain memory references and should
|
|
||||||
be avoided in hand-written assembly.
|
|
||||||
See the <a href="/doc/asm#x86">assembly documentation</a> for details.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h2 id="tools">Tools</h2>
|
|
||||||
|
|
||||||
<h3 id="cgo">Cgo</h3>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
There is one major change to <a href="/cmd/cgo/"><code>cgo</code></a>, along with one minor change.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
The major change is the definition of rules for sharing Go pointers with C code,
|
|
||||||
to ensure that such C code can coexist with Go's garbage collector.
|
|
||||||
Briefly, Go and C may share memory allocated by Go
|
|
||||||
when a pointer to that memory is passed to C as part of a <code>cgo</code> call,
|
|
||||||
provided that the memory itself contains no pointers to Go-allocated memory,
|
|
||||||
and provided that C does not retain the pointer after the call returns.
|
|
||||||
These rules are checked by the runtime during program execution:
|
|
||||||
if the runtime detects a violation, it prints a diagnosis and crashes the program.
|
|
||||||
The checks can be disabled by setting the environment variable
|
|
||||||
<code>GODEBUG=cgocheck=0</code>, but note that the vast majority of
|
|
||||||
code identified by the checks is subtly incompatible with garbage collection
|
|
||||||
in one way or another.
|
|
||||||
Disabling the checks will typically only lead to more mysterious failure modes.
|
|
||||||
Fixing the code in question should be strongly preferred
|
|
||||||
over turning off the checks.
|
|
||||||
See the <a href="/cmd/cgo/#hdr-Passing_pointers"><code>cgo</code> documentation</a> for more details.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
The minor change is
|
|
||||||
the addition of explicit <code>C.complexfloat</code> and <code>C.complexdouble</code> types,
|
|
||||||
separate from Go's <code>complex64</code> and <code>complex128</code>.
|
|
||||||
Matching the other numeric types, C's complex types and Go's complex type are
|
|
||||||
no longer interchangeable.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h3 id="compiler">Compiler Toolchain</h3>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
The compiler toolchain is mostly unchanged.
|
|
||||||
Internally, the most significant change is that the parser is now hand-written
|
|
||||||
instead of generated from <a href="/cmd/yacc/">yacc</a>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
The compiler, linker, and <code>go</code> command have a new flag <code>-msan</code>,
|
|
||||||
analogous to <code>-race</code> and only available on linux/amd64,
|
|
||||||
that enables interoperation with the <a href="https://clang.llvm.org/docs/MemorySanitizer.html">Clang MemorySanitizer</a>.
|
|
||||||
Such interoperation is useful mainly for testing a program containing suspect C or C++ code.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
The linker has a new option <code>-libgcc</code> to set the expected location
|
|
||||||
of the C compiler support library when linking <a href="/cmd/cgo/"><code>cgo</code></a> code.
|
|
||||||
The option is only consulted when using <code>-linkmode=internal</code>,
|
|
||||||
and it may be set to <code>none</code> to disable the use of a support library.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
The implementation of <a href="/doc/go1.5#link">build modes started in Go 1.5</a> has been expanded to more systems.
|
|
||||||
This release adds support for the <code>c-shared</code> mode on <code>android/386</code>, <code>android/amd64</code>,
|
|
||||||
<code>android/arm64</code>, <code>linux/386</code>, and <code>linux/arm64</code>;
|
|
||||||
for the <code>shared</code> mode on <code>linux/386</code>, <code>linux/arm</code>, <code>linux/amd64</code>, and <code>linux/ppc64le</code>;
|
|
||||||
and for the new <code>pie</code> mode (generating position-independent executables) on
|
|
||||||
<code>android/386</code>, <code>android/amd64</code>, <code>android/arm</code>, <code>android/arm64</code>, <code>linux/386</code>,
|
|
||||||
<code>linux/amd64</code>, <code>linux/arm</code>, <code>linux/arm64</code>, and <code>linux/ppc64le</code>.
|
|
||||||
See the <a href="https://golang.org/s/execmodes">design document</a> for details.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
As a reminder, the linker's <code>-X</code> flag changed in Go 1.5.
|
|
||||||
In Go 1.4 and earlier, it took two arguments, as in
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
-X importpath.name value
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Go 1.5 added an alternative syntax using a single argument
|
|
||||||
that is itself a <code>name=value</code> pair:
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
-X importpath.name=value
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
In Go 1.5 the old syntax was still accepted, after printing a warning
|
|
||||||
suggesting use of the new syntax instead.
|
|
||||||
Go 1.6 continues to accept the old syntax and print the warning.
|
|
||||||
Go 1.7 will remove support for the old syntax.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h3 id="gccgo">Gccgo</h3>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
The release schedules for the GCC and Go projects do not coincide.
|
|
||||||
GCC release 5 contains the Go 1.4 version of gccgo.
|
|
||||||
The next release, GCC 6, will have the Go 1.6.1 version of gccgo.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h3 id="go_command">Go command</h3>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
The <a href="/cmd/go"><code>go</code></a> command's basic operation
|
|
||||||
is unchanged, but there are a number of changes worth noting.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Go 1.5 introduced experimental support for vendoring,
|
|
||||||
enabled by setting the <code>GO15VENDOREXPERIMENT</code> environment variable to <code>1</code>.
|
|
||||||
Go 1.6 keeps the vendoring support, no longer considered experimental,
|
|
||||||
and enables it by default.
|
|
||||||
It can be disabled explicitly by setting
|
|
||||||
the <code>GO15VENDOREXPERIMENT</code> environment variable to <code>0</code>.
|
|
||||||
Go 1.7 will remove support for the environment variable.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
The most likely problem caused by enabling vendoring by default happens
|
|
||||||
in source trees containing an existing directory named <code>vendor</code> that
|
|
||||||
does not expect to be interpreted according to new vendoring semantics.
|
|
||||||
In this case, the simplest fix is to rename the directory to anything other
|
|
||||||
than <code>vendor</code> and update any affected import paths.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
For details about vendoring,
|
|
||||||
see the documentation for the <a href="/cmd/go/#hdr-Vendor_Directories"><code>go</code> command</a>
|
|
||||||
and the <a href="https://golang.org/s/go15vendor">design document</a>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
There is a new build flag, <code>-msan</code>,
|
|
||||||
that compiles Go with support for the LLVM memory sanitizer.
|
|
||||||
This is intended mainly for use when linking against C or C++ code
|
|
||||||
that is being checked with the memory sanitizer.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h3 id="doc_command">Go doc command</h3>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Go 1.5 introduced the
|
|
||||||
<a href="/cmd/go/#hdr-Show_documentation_for_package_or_symbol"><code>go doc</code></a> command,
|
|
||||||
which allows references to packages using only the package name, as in
|
|
||||||
<code>go</code> <code>doc</code> <code>http</code>.
|
|
||||||
In the event of ambiguity, the Go 1.5 behavior was to use the package
|
|
||||||
with the lexicographically earliest import path.
|
|
||||||
In Go 1.6, ambiguity is resolved by preferring import paths with
|
|
||||||
fewer elements, breaking ties using lexicographic comparison.
|
|
||||||
An important effect of this change is that original copies of packages
|
|
||||||
are now preferred over vendored copies.
|
|
||||||
Successful searches also tend to run faster.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h3 id="vet_command">Go vet command</h3>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
The <a href="/cmd/vet"><code>go vet</code></a> command now diagnoses
|
|
||||||
passing function or method values as arguments to <code>Printf</code>,
|
|
||||||
such as when passing <code>f</code> where <code>f()</code> was intended.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h2 id="performance">Performance</h2>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
As always, the changes are so general and varied that precise statements
|
|
||||||
about performance are difficult to make.
|
|
||||||
Some programs may run faster, some slower.
|
|
||||||
On average the programs in the Go 1 benchmark suite run a few percent faster in Go 1.6
|
|
||||||
than they did in Go 1.5.
|
|
||||||
The garbage collector's pauses are even lower than in Go 1.5,
|
|
||||||
especially for programs using
|
|
||||||
a large amount of memory.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
There have been significant optimizations bringing more than 10% improvements
|
|
||||||
to implementations of the
|
|
||||||
<a href="/pkg/compress/bzip2/"><code>compress/bzip2</code></a>,
|
|
||||||
<a href="/pkg/compress/gzip/"><code>compress/gzip</code></a>,
|
|
||||||
<a href="/pkg/crypto/aes/"><code>crypto/aes</code></a>,
|
|
||||||
<a href="/pkg/crypto/elliptic/"><code>crypto/elliptic</code></a>,
|
|
||||||
<a href="/pkg/crypto/ecdsa/"><code>crypto/ecdsa</code></a>, and
|
|
||||||
<a href="/pkg/sort/"><code>sort</code></a> packages.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h2 id="library">Core library</h2>
|
|
||||||
|
|
||||||
<h3 id="http2">HTTP/2</h3>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Go 1.6 adds transparent support in the
|
|
||||||
<a href="/pkg/net/http/"><code>net/http</code></a> package
|
|
||||||
for the new <a href="https://http2.github.io/">HTTP/2 protocol</a>.
|
|
||||||
Go clients and servers will automatically use HTTP/2 as appropriate when using HTTPS.
|
|
||||||
There is no exported API specific to details of the HTTP/2 protocol handling,
|
|
||||||
just as there is no exported API specific to HTTP/1.1.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Programs that must disable HTTP/2 can do so by setting
|
|
||||||
<a href="/pkg/net/http/#Transport"><code>Transport.TLSNextProto</code></a> (for clients)
|
|
||||||
or
|
|
||||||
<a href="/pkg/net/http/#Server"><code>Server.TLSNextProto</code></a> (for servers)
|
|
||||||
to a non-nil, empty map.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Programs that must adjust HTTP/2 protocol-specific details can import and use
|
|
||||||
<a href="https://golang.org/x/net/http2"><code>golang.org/x/net/http2</code></a>,
|
|
||||||
in particular its
|
|
||||||
<a href="https://godoc.org/golang.org/x/net/http2/#ConfigureServer">ConfigureServer</a>
|
|
||||||
and
|
|
||||||
<a href="https://godoc.org/golang.org/x/net/http2/#ConfigureTransport">ConfigureTransport</a>
|
|
||||||
functions.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h3 id="runtime">Runtime</h3>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
The runtime has added lightweight, best-effort detection of concurrent misuse of maps.
|
|
||||||
As always, if one goroutine is writing to a map, no other goroutine should be
|
|
||||||
reading or writing the map concurrently.
|
|
||||||
If the runtime detects this condition, it prints a diagnosis and crashes the program.
|
|
||||||
The best way to find out more about the problem is to run the program
|
|
||||||
under the
|
|
||||||
<a href="https://blog.golang.org/race-detector">race detector</a>,
|
|
||||||
which will more reliably identify the race
|
|
||||||
and give more detail.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
For program-ending panics, the runtime now by default
|
|
||||||
prints only the stack of the running goroutine,
|
|
||||||
not all existing goroutines.
|
|
||||||
Usually only the current goroutine is relevant to a panic,
|
|
||||||
so omitting the others significantly reduces irrelevant output
|
|
||||||
in a crash message.
|
|
||||||
To see the stacks from all goroutines in crash messages, set the environment variable
|
|
||||||
<code>GOTRACEBACK</code> to <code>all</code>
|
|
||||||
or call
|
|
||||||
<a href="/pkg/runtime/debug/#SetTraceback"><code>debug.SetTraceback</code></a>
|
|
||||||
before the crash, and rerun the program.
|
|
||||||
See the <a href="/pkg/runtime/#hdr-Environment_Variables">runtime documentation</a> for details.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
<em>Updating</em>:
|
|
||||||
Uncaught panics intended to dump the state of the entire program,
|
|
||||||
such as when a timeout is detected or when explicitly handling a received signal,
|
|
||||||
should now call <code>debug.SetTraceback("all")</code> before panicking.
|
|
||||||
Searching for uses of
|
|
||||||
<a href="/pkg/os/signal/#Notify"><code>signal.Notify</code></a> may help identify such code.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
On Windows, Go programs in Go 1.5 and earlier forced
|
|
||||||
the global Windows timer resolution to 1ms at startup
|
|
||||||
by calling <code>timeBeginPeriod(1)</code>.
|
|
||||||
Go no longer needs this for good scheduler performance,
|
|
||||||
and changing the global timer resolution caused problems on some systems,
|
|
||||||
so the call has been removed.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
When using <code>-buildmode=c-archive</code> or
|
|
||||||
<code>-buildmode=c-shared</code> to build an archive or a shared
|
|
||||||
library, the handling of signals has changed.
|
|
||||||
In Go 1.5 the archive or shared library would install a signal handler
|
|
||||||
for most signals.
|
|
||||||
In Go 1.6 it will only install a signal handler for the
|
|
||||||
synchronous signals needed to handle run-time panics in Go code:
|
|
||||||
SIGBUS, SIGFPE, SIGSEGV.
|
|
||||||
See the <a href="/pkg/os/signal">os/signal</a> package for more
|
|
||||||
details.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h3 id="reflect">Reflect</h3>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
The
|
|
||||||
<a href="/pkg/reflect/"><code>reflect</code></a> package has
|
|
||||||
<a href="https://golang.org/issue/12367">resolved a long-standing incompatibility</a>
|
|
||||||
between the gc and gccgo toolchains
|
|
||||||
regarding embedded unexported struct types containing exported fields.
|
|
||||||
Code that walks data structures using reflection, especially to implement
|
|
||||||
serialization in the spirit
|
|
||||||
of the
|
|
||||||
<a href="/pkg/encoding/json/"><code>encoding/json</code></a> and
|
|
||||||
<a href="/pkg/encoding/xml/"><code>encoding/xml</code></a> packages,
|
|
||||||
may need to be updated.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
The problem arises when using reflection to walk through
|
|
||||||
an embedded unexported struct-typed field
|
|
||||||
into an exported field of that struct.
|
|
||||||
In this case, <code>reflect</code> had incorrectly reported
|
|
||||||
the embedded field as exported, by returning an empty <code>Field.PkgPath</code>.
|
|
||||||
Now it correctly reports the field as unexported
|
|
||||||
but ignores that fact when evaluating access to exported fields
|
|
||||||
contained within the struct.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
<em>Updating</em>:
|
|
||||||
Typically, code that previously walked over structs and used
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
f.PkgPath != ""
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
to exclude inaccessible fields
|
|
||||||
should now use
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
f.PkgPath != "" && !f.Anonymous
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
For example, see the changes to the implementations of
|
|
||||||
<a href="https://go-review.googlesource.com/#/c/14011/2/src/encoding/json/encode.go"><code>encoding/json</code></a> and
|
|
||||||
<a href="https://go-review.googlesource.com/#/c/14012/2/src/encoding/xml/typeinfo.go"><code>encoding/xml</code></a>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h3 id="sort">Sorting</h3>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
In the
|
|
||||||
<a href="/pkg/sort/"><code>sort</code></a>
|
|
||||||
package,
|
|
||||||
the implementation of
|
|
||||||
<a href="/pkg/sort/#Sort"><code>Sort</code></a>
|
|
||||||
has been rewritten to make about 10% fewer calls to the
|
|
||||||
<a href="/pkg/sort/#Interface"><code>Interface</code></a>'s
|
|
||||||
<code>Less</code> and <code>Swap</code>
|
|
||||||
methods, with a corresponding overall time savings.
|
|
||||||
The new algorithm does choose a different ordering than before
|
|
||||||
for values that compare equal (those pairs for which <code>Less(i,</code> <code>j)</code> and <code>Less(j,</code> <code>i)</code> are false).
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
<em>Updating</em>:
|
|
||||||
The definition of <code>Sort</code> makes no guarantee about the final order of equal values,
|
|
||||||
but the new behavior may still break programs that expect a specific order.
|
|
||||||
Such programs should either refine their <code>Less</code> implementations
|
|
||||||
to report the desired order
|
|
||||||
or should switch to
|
|
||||||
<a href="/pkg/sort/#Stable"><code>Stable</code></a>,
|
|
||||||
which preserves the original input order
|
|
||||||
of equal values.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h3 id="template">Templates</h3>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
In the
|
|
||||||
<a href="/pkg/text/template/">text/template</a> package,
|
|
||||||
there are two significant new features to make writing templates easier.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
First, it is now possible to <a href="/pkg/text/template/#hdr-Text_and_spaces">trim spaces around template actions</a>,
|
|
||||||
which can make template definitions more readable.
|
|
||||||
A minus sign at the beginning of an action says to trim space before the action,
|
|
||||||
and a minus sign at the end of an action says to trim space after the action.
|
|
||||||
For example, the template
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
{{"{{"}}23 -}}
|
|
||||||
<
|
|
||||||
{{"{{"}}- 45}}
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
formats as <code>23<45</code>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Second, the new <a href="/pkg/text/template/#hdr-Actions"><code>{{"{{"}}block}}</code> action</a>,
|
|
||||||
combined with allowing redefinition of named templates,
|
|
||||||
provides a simple way to define pieces of a template that
|
|
||||||
can be replaced in different instantiations.
|
|
||||||
There is <a href="/pkg/text/template/#example_Template_block">an example</a>
|
|
||||||
in the <code>text/template</code> package that demonstrates this new feature.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h3 id="minor_library_changes">Minor changes to the library</h3>
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
The <a href="/pkg/archive/tar/"><code>archive/tar</code></a> package's
|
|
||||||
implementation corrects many bugs in rare corner cases of the file format.
|
|
||||||
One visible change is that the
|
|
||||||
<a href="/pkg/archive/tar/#Reader"><code>Reader</code></a> type's
|
|
||||||
<a href="/pkg/archive/tar/#Reader.Read"><code>Read</code></a> method
|
|
||||||
now presents the content of special file types as being empty,
|
|
||||||
returning <code>io.EOF</code> immediately.
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
In the <a href="/pkg/archive/zip/"><code>archive/zip</code></a> package, the
|
|
||||||
<a href="/pkg/archive/zip/#Reader"><code>Reader</code></a> type now has a
|
|
||||||
<a href="/pkg/archive/zip/#Reader.RegisterDecompressor"><code>RegisterDecompressor</code></a> method,
|
|
||||||
and the
|
|
||||||
<a href="/pkg/archive/zip/#Writer"><code>Writer</code></a> type now has a
|
|
||||||
<a href="/pkg/archive/zip/#Writer.RegisterCompressor"><code>RegisterCompressor</code></a> method,
|
|
||||||
enabling control over compression options for individual zip files.
|
|
||||||
These take precedence over the pre-existing global
|
|
||||||
<a href="/pkg/archive/zip/#RegisterDecompressor"><code>RegisterDecompressor</code></a> and
|
|
||||||
<a href="/pkg/archive/zip/#RegisterCompressor"><code>RegisterCompressor</code></a> functions.
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
The <a href="/pkg/bufio/"><code>bufio</code></a> package's
|
|
||||||
<a href="/pkg/bufio/#Scanner"><code>Scanner</code></a> type now has a
|
|
||||||
<a href="/pkg/bufio/#Scanner.Buffer"><code>Buffer</code></a> method,
|
|
||||||
to specify an initial buffer and maximum buffer size to use during scanning.
|
|
||||||
This makes it possible, when needed, to scan tokens larger than
|
|
||||||
<code>MaxScanTokenSize</code>.
|
|
||||||
Also for the <code>Scanner</code>, the package now defines the
|
|
||||||
<a href="/pkg/bufio/#ErrFinalToken"><code>ErrFinalToken</code></a> error value, for use by
|
|
||||||
<a href="/pkg/bufio/#SplitFunc">split functions</a> to abort processing or to return a final empty token.
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
The <a href="/pkg/compress/flate/"><code>compress/flate</code></a> package
|
|
||||||
has deprecated its
|
|
||||||
<a href="/pkg/compress/flate/#ReadError"><code>ReadError</code></a> and
|
|
||||||
<a href="/pkg/compress/flate/#WriteError"><code>WriteError</code></a> error implementations.
|
|
||||||
In Go 1.5 they were only rarely returned when an error was encountered;
|
|
||||||
now they are never returned, although they remain defined for compatibility.
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<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 report
|
|
||||||
<a href="/pkg/io/#ErrUnexpectedEOF"><code>io.ErrUnexpectedEOF</code></a> for truncated input streams, instead of
|
|
||||||
<a href="/pkg/io/#EOF"><code>io.EOF</code></a>.
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
The <a href="/pkg/crypto/cipher/"><code>crypto/cipher</code></a> package now
|
|
||||||
overwrites the destination buffer in the event of a GCM decryption failure.
|
|
||||||
This is to allow the AESNI code to avoid using a temporary buffer.
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
The <a href="/pkg/crypto/tls/"><code>crypto/tls</code></a> package
|
|
||||||
has a variety of minor changes.
|
|
||||||
It now allows
|
|
||||||
<a href="/pkg/crypto/tls/#Listen"><code>Listen</code></a>
|
|
||||||
to succeed when the
|
|
||||||
<a href="/pkg/crypto/tls/#Config"><code>Config</code></a>
|
|
||||||
has a nil <code>Certificates</code>, as long as the <code>GetCertificate</code> callback is set,
|
|
||||||
it adds support for RSA with AES-GCM cipher suites,
|
|
||||||
and
|
|
||||||
it adds a
|
|
||||||
<a href="/pkg/crypto/tls/#RecordHeaderError"><code>RecordHeaderError</code></a>
|
|
||||||
to allow clients (in particular, the <a href="/pkg/net/http/"><code>net/http</code></a> package)
|
|
||||||
to report a better error when attempting a TLS connection to a non-TLS server.
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
The <a href="/pkg/crypto/x509/"><code>crypto/x509</code></a> package
|
|
||||||
now permits certificates to contain negative serial numbers
|
|
||||||
(technically an error, but unfortunately common in practice),
|
|
||||||
and it defines a new
|
|
||||||
<a href="/pkg/crypto/x509/#InsecureAlgorithmError"><code>InsecureAlgorithmError</code></a>
|
|
||||||
to give a better error message when rejecting a certificate
|
|
||||||
signed with an insecure algorithm like MD5.
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
The <a href="/pkg/debug/dwarf"><code>debug/dwarf</code></a> and
|
|
||||||
<a href="/pkg/debug/elf/"><code>debug/elf</code></a> packages
|
|
||||||
together add support for compressed DWARF sections.
|
|
||||||
User code needs no updating: the sections are decompressed automatically when read.
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
The <a href="/pkg/debug/elf/"><code>debug/elf</code></a> package
|
|
||||||
adds support for general compressed ELF sections.
|
|
||||||
User code needs no updating: the sections are decompressed automatically when read.
|
|
||||||
However, compressed
|
|
||||||
<a href="/pkg/debug/elf/#Section"><code>Sections</code></a> do not support random access:
|
|
||||||
they have a nil <code>ReaderAt</code> field.
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
The <a href="/pkg/encoding/asn1/"><code>encoding/asn1</code></a> package
|
|
||||||
now exports
|
|
||||||
<a href="/pkg/encoding/asn1/#pkg-constants">tag and class constants</a>
|
|
||||||
useful for advanced parsing of ASN.1 structures.
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
Also in the <a href="/pkg/encoding/asn1/"><code>encoding/asn1</code></a> package,
|
|
||||||
<a href="/pkg/encoding/asn1/#Unmarshal"><code>Unmarshal</code></a> now rejects various non-standard integer and length encodings.
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
The <a href="/pkg/encoding/base64"><code>encoding/base64</code></a> package's
|
|
||||||
<a href="/pkg/encoding/base64/#Decoder"><code>Decoder</code></a> has been fixed
|
|
||||||
to process the final bytes of its input. Previously it processed as many four-byte tokens as
|
|
||||||
possible but ignored the remainder, up to three bytes.
|
|
||||||
The <code>Decoder</code> therefore now handles inputs in unpadded encodings (like
|
|
||||||
<a href="/pkg/encoding/base64/#RawURLEncoding">RawURLEncoding</a>) correctly,
|
|
||||||
but it also rejects inputs in padded encodings that are truncated or end with invalid bytes,
|
|
||||||
such as trailing spaces.
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
The <a href="/pkg/encoding/json/"><code>encoding/json</code></a> package
|
|
||||||
now checks the syntax of a
|
|
||||||
<a href="/pkg/encoding/json/#Number"><code>Number</code></a>
|
|
||||||
before marshaling it, requiring that it conforms to the JSON specification for numeric values.
|
|
||||||
As in previous releases, the zero <code>Number</code> (an empty string) is marshaled as a literal 0 (zero).
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
The <a href="/pkg/encoding/xml/"><code>encoding/xml</code></a> package's
|
|
||||||
<a href="/pkg/encoding/xml/#Marshal"><code>Marshal</code></a>
|
|
||||||
function now supports a <code>cdata</code> attribute, such as <code>chardata</code>
|
|
||||||
but encoding its argument in one or more <code><![CDATA[ ... ]]></code> tags.
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
Also in the <a href="/pkg/encoding/xml/"><code>encoding/xml</code></a> package,
|
|
||||||
<a href="/pkg/encoding/xml/#Decoder"><code>Decoder</code></a>'s
|
|
||||||
<a href="/pkg/encoding/xml/#Decoder.Token"><code>Token</code></a> method
|
|
||||||
now reports an error when encountering EOF before seeing all open tags closed,
|
|
||||||
consistent with its general requirement that tags in the input be properly matched.
|
|
||||||
To avoid that requirement, use
|
|
||||||
<a href="/pkg/encoding/xml/#Decoder.RawToken"><code>RawToken</code></a>.
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
The <a href="/pkg/fmt/"><code>fmt</code></a> package now allows
|
|
||||||
any integer type as an argument to
|
|
||||||
<a href="/pkg/fmt/#Printf"><code>Printf</code></a>'s <code>*</code> width and precision specification.
|
|
||||||
In previous releases, the argument to <code>*</code> was required to have type <code>int</code>.
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
Also in the <a href="/pkg/fmt/"><code>fmt</code></a> package,
|
|
||||||
<a href="/pkg/fmt/#Scanf"><code>Scanf</code></a> can now scan hexadecimal strings using %X, as an alias for %x.
|
|
||||||
Both formats accept any mix of upper- and lower-case hexadecimal.
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
The <a href="/pkg/image/"><code>image</code></a>
|
|
||||||
and
|
|
||||||
<a href="/pkg/image/color/"><code>image/color</code></a> packages
|
|
||||||
add
|
|
||||||
<a href="/pkg/image/#NYCbCrA"><code>NYCbCrA</code></a>
|
|
||||||
and
|
|
||||||
<a href="/pkg/image/color/#NYCbCrA"><code>NYCbCrA</code></a>
|
|
||||||
types, to support Y'CbCr images with non-premultiplied alpha.
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
The <a href="/pkg/io/"><code>io</code></a> package's
|
|
||||||
<a href="/pkg/io/#MultiWriter"><code>MultiWriter</code></a>
|
|
||||||
implementation now implements a <code>WriteString</code> method,
|
|
||||||
for use by
|
|
||||||
<a href="/pkg/io/#WriteString"><code>WriteString</code></a>.
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
In the <a href="/pkg/math/big/"><code>math/big</code></a> package,
|
|
||||||
<a href="/pkg/math/big/#Int"><code>Int</code></a> adds
|
|
||||||
<a href="/pkg/math/big/#Int.Append"><code>Append</code></a>
|
|
||||||
and
|
|
||||||
<a href="/pkg/math/big/#Int.Text"><code>Text</code></a>
|
|
||||||
methods to give more control over printing.
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
Also in the <a href="/pkg/math/big/"><code>math/big</code></a> package,
|
|
||||||
<a href="/pkg/math/big/#Float"><code>Float</code></a> now implements
|
|
||||||
<a href="/pkg/encoding/#TextMarshaler"><code>encoding.TextMarshaler</code></a> and
|
|
||||||
<a href="/pkg/encoding/#TextUnmarshaler"><code>encoding.TextUnmarshaler</code></a>,
|
|
||||||
allowing it to be serialized in a natural form by the
|
|
||||||
<a href="/pkg/encoding/json/"><code>encoding/json</code></a> and
|
|
||||||
<a href="/pkg/encoding/xml/"><code>encoding/xml</code></a> packages.
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
Also in the <a href="/pkg/math/big/"><code>math/big</code></a> package,
|
|
||||||
<a href="/pkg/math/big/#Float"><code>Float</code></a>'s
|
|
||||||
<a href="/pkg/math/big/#Float.Append"><code>Append</code></a> method now supports the special precision argument -1.
|
|
||||||
As in
|
|
||||||
<a href="/pkg/strconv/#ParseFloat"><code>strconv.ParseFloat</code></a>,
|
|
||||||
precision -1 means to use the smallest number of digits necessary such that
|
|
||||||
<a href="/pkg/math/big/#Float.Parse"><code>Parse</code></a>
|
|
||||||
reading the result into a <code>Float</code> of the same precision
|
|
||||||
will yield the original value.
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
The <a href="/pkg/math/rand/"><code>math/rand</code></a> package
|
|
||||||
adds a
|
|
||||||
<a href="/pkg/math/rand/#Read"><code>Read</code></a>
|
|
||||||
function, and likewise
|
|
||||||
<a href="/pkg/math/rand/#Rand"><code>Rand</code></a> adds a
|
|
||||||
<a href="/pkg/math/rand/#Rand.Read"><code>Read</code></a> method.
|
|
||||||
These make it easier to generate pseudorandom test data.
|
|
||||||
Note that, like the rest of the package,
|
|
||||||
these should not be used in cryptographic settings;
|
|
||||||
for such purposes, use the <a href="/pkg/crypto/rand/"><code>crypto/rand</code></a> package instead.
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
The <a href="/pkg/net/"><code>net</code></a> package's
|
|
||||||
<a href="/pkg/net/#ParseMAC"><code>ParseMAC</code></a> function now accepts 20-byte IP-over-InfiniBand (IPoIB) link-layer addresses.
|
|
||||||
</li>
|
|
||||||
|
|
||||||
|
|
||||||
<li>
|
|
||||||
Also in the <a href="/pkg/net/"><code>net</code></a> package,
|
|
||||||
there have been a few changes to DNS lookups.
|
|
||||||
First, the
|
|
||||||
<a href="/pkg/net/#DNSError"><code>DNSError</code></a> error implementation now implements
|
|
||||||
<a href="/pkg/net/#Error"><code>Error</code></a>,
|
|
||||||
and in particular its new
|
|
||||||
<a href="/pkg/net/#DNSError.IsTemporary"><code>IsTemporary</code></a>
|
|
||||||
method returns true for DNS server errors.
|
|
||||||
Second, DNS lookup functions such as
|
|
||||||
<a href="/pkg/net/#LookupAddr"><code>LookupAddr</code></a>
|
|
||||||
now return rooted domain names (with a trailing dot)
|
|
||||||
on Plan 9 and Windows, to match the behavior of Go on Unix systems.
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
The <a href="/pkg/net/http/"><code>net/http</code></a> package has
|
|
||||||
a number of minor additions beyond the HTTP/2 support already discussed.
|
|
||||||
First, the
|
|
||||||
<a href="/pkg/net/http/#FileServer"><code>FileServer</code></a> now sorts its generated directory listings by file name.
|
|
||||||
Second, the
|
|
||||||
<a href="/pkg/net/http/#ServeFile"><code>ServeFile</code></a> function now refuses to serve a result
|
|
||||||
if the request's URL path contains “..” (dot-dot) as a path element.
|
|
||||||
Programs should typically use <code>FileServer</code> and
|
|
||||||
<a href="/pkg/net/http/#Dir"><code>Dir</code></a>
|
|
||||||
instead of calling <code>ServeFile</code> directly.
|
|
||||||
Programs that need to serve file content in response to requests for URLs containing dot-dot can
|
|
||||||
still call <a href="/pkg/net/http/#ServeContent"><code>ServeContent</code></a>.
|
|
||||||
Third, the
|
|
||||||
<a href="/pkg/net/http/#Client"><code>Client</code></a> now allows user code to set the
|
|
||||||
<code>Expect:</code> <code>100-continue</code> header (see
|
|
||||||
<a href="/pkg/net/http/#Transport"><code>Transport.ExpectContinueTimeout</code></a>).
|
|
||||||
Fourth, there are
|
|
||||||
<a href="/pkg/net/http/#pkg-constants">five new error codes</a>:
|
|
||||||
<code>StatusPreconditionRequired</code> (428),
|
|
||||||
<code>StatusTooManyRequests</code> (429),
|
|
||||||
<code>StatusRequestHeaderFieldsTooLarge</code> (431), and
|
|
||||||
<code>StatusNetworkAuthenticationRequired</code> (511) from RFC 6585,
|
|
||||||
as well as the recently-approved
|
|
||||||
<code>StatusUnavailableForLegalReasons</code> (451).
|
|
||||||
Fifth, the implementation and documentation of
|
|
||||||
<a href="/pkg/net/http/#CloseNotifier"><code>CloseNotifier</code></a>
|
|
||||||
has been substantially changed.
|
|
||||||
The <a href="/pkg/net/http/#Hijacker"><code>Hijacker</code></a>
|
|
||||||
interface now works correctly on connections that have previously
|
|
||||||
been used with <code>CloseNotifier</code>.
|
|
||||||
The documentation now describes when <code>CloseNotifier</code>
|
|
||||||
is expected to work.
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
Also in the <a href="/pkg/net/http/"><code>net/http</code></a> package,
|
|
||||||
there are a few changes related to the handling of a
|
|
||||||
<a href="/pkg/net/http/#Request"><code>Request</code></a> data structure with its <code>Method</code> field set to the empty string.
|
|
||||||
An empty <code>Method</code> field has always been documented as an alias for <code>"GET"</code>
|
|
||||||
and it remains so.
|
|
||||||
However, Go 1.6 fixes a few routines that did not treat an empty
|
|
||||||
<code>Method</code> the same as an explicit <code>"GET"</code>.
|
|
||||||
Most notably, in previous releases
|
|
||||||
<a href="/pkg/net/http/#Client"><code>Client</code></a> followed redirects only with
|
|
||||||
<code>Method</code> set explicitly to <code>"GET"</code>;
|
|
||||||
in Go 1.6 <code>Client</code> also follows redirects for the empty <code>Method</code>.
|
|
||||||
Finally,
|
|
||||||
<a href="/pkg/net/http/#NewRequest"><code>NewRequest</code></a> accepts a <code>method</code> argument that has not been
|
|
||||||
documented as allowed to be empty.
|
|
||||||
In past releases, passing an empty <code>method</code> argument resulted
|
|
||||||
in a <code>Request</code> with an empty <code>Method</code> field.
|
|
||||||
In Go 1.6, the resulting <code>Request</code> always has an initialized
|
|
||||||
<code>Method</code> field: if its argument is an empty string, <code>NewRequest</code>
|
|
||||||
sets the <code>Method</code> field in the returned <code>Request</code> to <code>"GET"</code>.
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
The <a href="/pkg/net/http/httptest/"><code>net/http/httptest</code></a> package's
|
|
||||||
<a href="/pkg/net/http/httptest/#ResponseRecorder"><code>ResponseRecorder</code></a> now initializes a default Content-Type header
|
|
||||||
using the same content-sniffing algorithm as in
|
|
||||||
<a href="/pkg/net/http/#Server"><code>http.Server</code></a>.
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
The <a href="/pkg/net/url/"><code>net/url</code></a> package's
|
|
||||||
<a href="/pkg/net/url/#Parse"><code>Parse</code></a> is now stricter and more spec-compliant regarding the parsing
|
|
||||||
of host names.
|
|
||||||
For example, spaces in the host name are no longer accepted.
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
Also in the <a href="/pkg/net/url/"><code>net/url</code></a> package,
|
|
||||||
the <a href="/pkg/net/url/#Error"><code>Error</code></a> type now implements
|
|
||||||
<a href="/pkg/net/#Error"><code>net.Error</code></a>.
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
The <a href="/pkg/os/"><code>os</code></a> package's
|
|
||||||
<a href="/pkg/os/#IsExist"><code>IsExist</code></a>,
|
|
||||||
<a href="/pkg/os/#IsNotExist"><code>IsNotExist</code></a>,
|
|
||||||
and
|
|
||||||
<a href="/pkg/os/#IsPermission"><code>IsPermission</code></a>
|
|
||||||
now return correct results when inquiring about an
|
|
||||||
<a href="/pkg/os/#SyscallError"><code>SyscallError</code></a>.
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
On Unix-like systems, when a write
|
|
||||||
to <a href="/pkg/os/#pkg-variables"><code>os.Stdout</code>
|
|
||||||
or <code>os.Stderr</code></a> (more precisely, an <code>os.File</code>
|
|
||||||
opened for file descriptor 1 or 2) fails due to a broken pipe error,
|
|
||||||
the program will raise a <code>SIGPIPE</code> signal.
|
|
||||||
By default this will cause the program to exit; this may be changed by
|
|
||||||
calling the
|
|
||||||
<a href="/pkg/os/signal"><code>os/signal</code></a>
|
|
||||||
<a href="/pkg/os/signal/#Notify"><code>Notify</code></a> function
|
|
||||||
for <code>syscall.SIGPIPE</code>.
|
|
||||||
A write to a broken pipe on a file descriptor other 1 or 2 will simply
|
|
||||||
return <code>syscall.EPIPE</code> (possibly wrapped in
|
|
||||||
<a href="/pkg/os#PathError"><code>os.PathError</code></a>
|
|
||||||
and/or <a href="/pkg/os#SyscallError"><code>os.SyscallError</code></a>)
|
|
||||||
to the caller.
|
|
||||||
The old behavior of raising an uncatchable <code>SIGPIPE</code> signal
|
|
||||||
after 10 consecutive writes to a broken pipe no longer occurs.
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
In the <a href="/pkg/os/exec/"><code>os/exec</code></a> package,
|
|
||||||
<a href="/pkg/os/exec/#Cmd"><code>Cmd</code></a>'s
|
|
||||||
<a href="/pkg/os/exec/#Cmd.Output"><code>Output</code></a> method continues to return an
|
|
||||||
<a href="/pkg/os/exec/#ExitError"><code>ExitError</code></a> when a command exits with an unsuccessful status.
|
|
||||||
If standard error would otherwise have been discarded,
|
|
||||||
the returned <code>ExitError</code> now holds a prefix and suffix
|
|
||||||
(currently 32 kB) of the failed command's standard error output,
|
|
||||||
for debugging or for inclusion in error messages.
|
|
||||||
The <code>ExitError</code>'s
|
|
||||||
<a href="/pkg/os/exec/#ExitError.String"><code>String</code></a>
|
|
||||||
method does not show the captured standard error;
|
|
||||||
programs must retrieve it from the data structure
|
|
||||||
separately.
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
On Windows, the <a href="/pkg/path/filepath/"><code>path/filepath</code></a> package's
|
|
||||||
<a href="/pkg/path/filepath/#Join"><code>Join</code></a> function now correctly handles the case when the base is a relative drive path.
|
|
||||||
For example, <code>Join(`c:`,</code> <code>`a`)</code> now
|
|
||||||
returns <code>`c:a`</code> instead of <code>`c:\a`</code> as in past releases.
|
|
||||||
This may affect code that expects the incorrect result.
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
In the <a href="/pkg/regexp/"><code>regexp</code></a> package,
|
|
||||||
the
|
|
||||||
<a href="/pkg/regexp/#Regexp"><code>Regexp</code></a> type has always been safe for use by
|
|
||||||
concurrent goroutines.
|
|
||||||
It uses a <a href="/pkg/sync/#Mutex"><code>sync.Mutex</code></a> to protect
|
|
||||||
a cache of scratch spaces used during regular expression searches.
|
|
||||||
Some high-concurrency servers using the same <code>Regexp</code> from many goroutines
|
|
||||||
have seen degraded performance due to contention on that mutex.
|
|
||||||
To help such servers, <code>Regexp</code> now has a
|
|
||||||
<a href="/pkg/regexp/#Regexp.Copy"><code>Copy</code></a> method,
|
|
||||||
which makes a copy of a <code>Regexp</code> that shares most of the structure
|
|
||||||
of the original but has its own scratch space cache.
|
|
||||||
Two goroutines can use different copies of a <code>Regexp</code>
|
|
||||||
without mutex contention.
|
|
||||||
A copy does have additional space overhead, so <code>Copy</code>
|
|
||||||
should only be used when contention has been observed.
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
The <a href="/pkg/strconv/"><code>strconv</code></a> package adds
|
|
||||||
<a href="/pkg/strconv/#IsGraphic"><code>IsGraphic</code></a>,
|
|
||||||
similar to <a href="/pkg/strconv/#IsPrint"><code>IsPrint</code></a>.
|
|
||||||
It also adds
|
|
||||||
<a href="/pkg/strconv/#QuoteToGraphic"><code>QuoteToGraphic</code></a>,
|
|
||||||
<a href="/pkg/strconv/#QuoteRuneToGraphic"><code>QuoteRuneToGraphic</code></a>,
|
|
||||||
<a href="/pkg/strconv/#AppendQuoteToGraphic"><code>AppendQuoteToGraphic</code></a>,
|
|
||||||
and
|
|
||||||
<a href="/pkg/strconv/#AppendQuoteRuneToGraphic"><code>AppendQuoteRuneToGraphic</code></a>,
|
|
||||||
analogous to
|
|
||||||
<a href="/pkg/strconv/#QuoteToASCII"><code>QuoteToASCII</code></a>,
|
|
||||||
<a href="/pkg/strconv/#QuoteRuneToASCII"><code>QuoteRuneToASCII</code></a>,
|
|
||||||
and so on.
|
|
||||||
The <code>ASCII</code> family escapes all space characters except ASCII space (U+0020).
|
|
||||||
In contrast, the <code>Graphic</code> family does not escape any Unicode space characters (category Zs).
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
In the <a href="/pkg/testing/"><code>testing</code></a> package,
|
|
||||||
when a test calls
|
|
||||||
<a href="/pkg/testing/#T.Parallel">t.Parallel</a>,
|
|
||||||
that test is paused until all non-parallel tests complete, and then
|
|
||||||
that test continues execution with all other parallel tests.
|
|
||||||
Go 1.6 changes the time reported for such a test:
|
|
||||||
previously the time counted only the parallel execution,
|
|
||||||
but now it also counts the time from the start of testing
|
|
||||||
until the call to <code>t.Parallel</code>.
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
The <a href="/pkg/text/template/"><code>text/template</code></a> package
|
|
||||||
contains two minor changes, in addition to the <a href="#template">major changes</a>
|
|
||||||
described above.
|
|
||||||
First, it adds a new
|
|
||||||
<a href="/pkg/text/template/#ExecError"><code>ExecError</code></a> type
|
|
||||||
returned for any error during
|
|
||||||
<a href="/pkg/text/template/#Template.Execute"><code>Execute</code></a>
|
|
||||||
that does not originate in a <code>Write</code> to the underlying writer.
|
|
||||||
Callers can distinguish template usage errors from I/O errors by checking for
|
|
||||||
<code>ExecError</code>.
|
|
||||||
Second, the
|
|
||||||
<a href="/pkg/text/template/#Template.Funcs"><code>Funcs</code></a> method
|
|
||||||
now checks that the names used as keys in the
|
|
||||||
<a href="/pkg/text/template/#FuncMap"><code>FuncMap</code></a>
|
|
||||||
are identifiers that can appear in a template function invocation.
|
|
||||||
If not, <code>Funcs</code> panics.
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
The <a href="/pkg/time/"><code>time</code></a> package's
|
|
||||||
<a href="/pkg/time/#Parse"><code>Parse</code></a> function has always rejected any day of month larger than 31,
|
|
||||||
such as January 32.
|
|
||||||
In Go 1.6, <code>Parse</code> now also rejects February 29 in non-leap years,
|
|
||||||
February 30, February 31, April 31, June 31, September 31, and November 31.
|
|
||||||
</li>
|
|
||||||
|
|
||||||
</ul>
|
|
||||||
|
|
1281
doc/go1.7.html
1666
doc/go1.8.html
1024
doc/go1.9.html
2038
doc/go1.html
|
@ -1,202 +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>
|
|
||||||
Methods. As with struct fields, it may be necessary to add methods
|
|
||||||
to types.
|
|
||||||
Under some circumstances, such as when the type is embedded in
|
|
||||||
a struct along with another type,
|
|
||||||
the addition of the new method may break
|
|
||||||
the struct by creating a conflict with an existing method of the other
|
|
||||||
embedded type.
|
|
||||||
We cannot protect against this rare case and do not guarantee compatibility
|
|
||||||
should it arise.
|
|
||||||
</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="//golang.org/x/net">golang.org/x/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="//golang.org/x/sys">go.sys</a> subrepository.
|
|
||||||
For details and background, see
|
|
||||||
<a href="//golang.org/s/go1.4-syscall">this document</a>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h2 id="tools">Tools</h2>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Finally, the Go toolchain (compilers, linkers, build tools, and so
|
|
||||||
on) is 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>
|
|
2475
doc/go_faq.html
|
@ -1,6 +1,6 @@
|
||||||
<!--{
|
<!--{
|
||||||
"Title": "The Go Programming Language Specification",
|
"Title": "The Go Programming Language Specification",
|
||||||
"Subtitle": "Version of Feb 2, 2021",
|
"Subtitle": "Version of Feb 10, 2021",
|
||||||
"Path": "/ref/spec"
|
"Path": "/ref/spec"
|
||||||
}-->
|
}-->
|
||||||
|
|
||||||
|
@ -3446,7 +3446,7 @@ In a function call, the function value and arguments are evaluated in
|
||||||
After they are evaluated, the parameters of the call are passed by value to the function
|
After they are evaluated, the parameters of the call are passed by value to the function
|
||||||
and the called function begins execution.
|
and the called function begins execution.
|
||||||
The return parameters of the function are passed by value
|
The return parameters of the function are passed by value
|
||||||
back to the calling function when the function returns.
|
back to the caller when the function returns.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
The Go gopher was designed by Renee French. (http://reneefrench.blogspot.com/)
|
|
||||||
The design is licensed under the Creative Commons 3.0 Attributions license.
|
|
||||||
Read this article for more details: https://blog.golang.org/gopher
|
|
Двоичные данные
doc/gopher/appenginegopher.jpg
До Ширина: | Высота: | Размер: 133 KiB |
Двоичные данные
doc/gopher/appenginegophercolor.jpg
До Ширина: | Высота: | Размер: 158 KiB |
Двоичные данные
doc/gopher/appenginelogo.gif
До Ширина: | Высота: | Размер: 2.1 KiB |
Двоичные данные
doc/gopher/biplane.jpg
До Ширина: | Высота: | Размер: 199 KiB |
Двоичные данные
doc/gopher/bumper.png
До Ширина: | Высота: | Размер: 270 KiB |
Двоичные данные
doc/gopher/bumper192x108.png
До Ширина: | Высота: | Размер: 8.2 KiB |
Двоичные данные
doc/gopher/bumper320x180.png
До Ширина: | Высота: | Размер: 15 KiB |
Двоичные данные
doc/gopher/bumper480x270.png
До Ширина: | Высота: | Размер: 26 KiB |
Двоичные данные
doc/gopher/bumper640x360.png
До Ширина: | Высота: | Размер: 41 KiB |
Двоичные данные
doc/gopher/doc.png
До Ширина: | Высота: | Размер: 4.3 KiB |
|
@ -1,238 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
|
||||||
|
|
||||||
<svg
|
|
||||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
|
||||||
xmlns:cc="http://creativecommons.org/ns#"
|
|
||||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
|
||||||
xmlns:svg="http://www.w3.org/2000/svg"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
|
||||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
|
||||||
width="32"
|
|
||||||
height="32"
|
|
||||||
viewBox="0 0 32 32.000001"
|
|
||||||
id="svg4416"
|
|
||||||
version="1.1"
|
|
||||||
inkscape:version="0.91 r13725"
|
|
||||||
sodipodi:docname="favicon.svg"
|
|
||||||
inkscape:export-filename="../../favicon.png"
|
|
||||||
inkscape:export-xdpi="90"
|
|
||||||
inkscape:export-ydpi="90">
|
|
||||||
<defs
|
|
||||||
id="defs4418" />
|
|
||||||
<sodipodi:namedview
|
|
||||||
id="base"
|
|
||||||
pagecolor="#ffffff"
|
|
||||||
bordercolor="#666666"
|
|
||||||
borderopacity="1.0"
|
|
||||||
inkscape:pageopacity="0.0"
|
|
||||||
inkscape:pageshadow="2"
|
|
||||||
inkscape:zoom="15.839192"
|
|
||||||
inkscape:cx="17.966652"
|
|
||||||
inkscape:cy="9.2991824"
|
|
||||||
inkscape:document-units="px"
|
|
||||||
inkscape:current-layer="layer1"
|
|
||||||
showgrid="true"
|
|
||||||
units="px"
|
|
||||||
inkscape:snap-bbox="true"
|
|
||||||
inkscape:snap-bbox-edge-midpoints="false"
|
|
||||||
inkscape:bbox-nodes="true"
|
|
||||||
showguides="false"
|
|
||||||
inkscape:window-width="1920"
|
|
||||||
inkscape:window-height="1018"
|
|
||||||
inkscape:window-x="1912"
|
|
||||||
inkscape:window-y="-8"
|
|
||||||
inkscape:window-maximized="1"
|
|
||||||
inkscape:object-nodes="true"
|
|
||||||
inkscape:snap-smooth-nodes="true"
|
|
||||||
inkscape:snap-global="false">
|
|
||||||
<inkscape:grid
|
|
||||||
type="xygrid"
|
|
||||||
id="grid5148" />
|
|
||||||
</sodipodi:namedview>
|
|
||||||
<metadata
|
|
||||||
id="metadata4421">
|
|
||||||
<rdf:RDF>
|
|
||||||
<cc:Work
|
|
||||||
rdf:about="">
|
|
||||||
<dc:format>image/svg+xml</dc:format>
|
|
||||||
<dc:type
|
|
||||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
|
||||||
<dc:title />
|
|
||||||
</cc:Work>
|
|
||||||
</rdf:RDF>
|
|
||||||
</metadata>
|
|
||||||
<g
|
|
||||||
inkscape:label="icon"
|
|
||||||
inkscape:groupmode="layer"
|
|
||||||
id="layer1"
|
|
||||||
transform="translate(0,-1020.3622)">
|
|
||||||
<ellipse
|
|
||||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#384e54;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
|
||||||
id="ellipse4216"
|
|
||||||
cx="-907.35657"
|
|
||||||
cy="479.90009"
|
|
||||||
rx="3.5793996"
|
|
||||||
ry="3.8207953"
|
|
||||||
transform="matrix(-0.49169095,-0.87076978,-0.87076978,0.49169095,0,0)"
|
|
||||||
inkscape:transform-center-x="0.67794294"
|
|
||||||
inkscape:transform-center-y="-2.3634048" />
|
|
||||||
<ellipse
|
|
||||||
inkscape:transform-center-y="-2.3633882"
|
|
||||||
inkscape:transform-center-x="-0.67793718"
|
|
||||||
transform="matrix(0.49169095,-0.87076978,0.87076978,0.49169095,0,0)"
|
|
||||||
ry="3.8207953"
|
|
||||||
rx="3.5793996"
|
|
||||||
cy="507.8461"
|
|
||||||
cx="-891.57654"
|
|
||||||
id="ellipse4463"
|
|
||||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#384e54;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
|
|
||||||
<path
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#384e54;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
|
||||||
d="m 16.091693,1021.3642 c -1.105749,0.01 -2.210341,0.049 -3.31609,0.09 C 6.8422558,1021.6738 2,1026.3942 2,1032.3622 c 0,2.9786 0,13 0,20 l 28,0 c 0,-8 0,-16 0,-20 0,-5.9683 -4.667345,-10.4912 -10.59023,-10.908 -1.10575,-0.078 -2.212328,-0.099 -3.318077,-0.09 z"
|
|
||||||
id="path4465"
|
|
||||||
sodipodi:nodetypes="ccsccscc" />
|
|
||||||
<path
|
|
||||||
inkscape:transform-center-y="-1.3604657"
|
|
||||||
inkscape:transform-center-x="-0.98424303"
|
|
||||||
sodipodi:nodetypes="sssssss"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
id="path4469"
|
|
||||||
d="m 4.6078867,1025.0462 c 0.459564,0.2595 1.818262,1.2013 1.980983,1.648 0.183401,0.5035 0.159385,1.0657 -0.114614,1.551 -0.346627,0.6138 -1.005341,0.9487 -1.696421,0.9365 -0.339886,-0.01 -1.720283,-0.6372 -2.042561,-0.8192 -0.97754,-0.5519 -1.350795,-1.7418 -0.833686,-2.6576 0.517109,-0.9158 1.728749,-1.2107 2.706299,-0.6587 z"
|
|
||||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#76e1fe;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
|
|
||||||
<rect
|
|
||||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#000000;fill-opacity:0.32850246;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
|
||||||
id="rect4473"
|
|
||||||
width="3.0866659"
|
|
||||||
height="3.5313663"
|
|
||||||
x="14.406213"
|
|
||||||
y="1035.6842"
|
|
||||||
ry="0.62426329" />
|
|
||||||
<path
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#76e1fe;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
|
||||||
d="m 16,1023.3622 c -9,0 -12,3.7153 -12,9 l 0,20 24,0 c -0.04889,-7.3562 0,-18 0,-20 0,-5.2848 -3,-9 -12,-9 z"
|
|
||||||
id="path4471"
|
|
||||||
sodipodi:nodetypes="zsccsz" />
|
|
||||||
<path
|
|
||||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#76e1fe;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
|
||||||
d="m 27.074073,1025.0462 c -0.45957,0.2595 -1.818257,1.2013 -1.980979,1.648 -0.183401,0.5035 -0.159384,1.0657 0.114614,1.551 0.346627,0.6138 1.005335,0.9487 1.696415,0.9365 0.33988,-0.01 1.72029,-0.6372 2.04256,-0.8192 0.97754,-0.5519 1.35079,-1.7418 0.83369,-2.6576 -0.51711,-0.9158 -1.72876,-1.2107 -2.7063,-0.6587 z"
|
|
||||||
id="path4481"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
sodipodi:nodetypes="sssssss"
|
|
||||||
inkscape:transform-center-x="0.98424094"
|
|
||||||
inkscape:transform-center-y="-1.3604657" />
|
|
||||||
<circle
|
|
||||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
|
||||||
id="circle4477"
|
|
||||||
cx="21.175734"
|
|
||||||
cy="1030.3542"
|
|
||||||
r="4.6537542"
|
|
||||||
inkscape:export-filename=".\rect4485.png"
|
|
||||||
inkscape:export-xdpi="90"
|
|
||||||
inkscape:export-ydpi="90" />
|
|
||||||
<circle
|
|
||||||
r="4.8316345"
|
|
||||||
cy="1030.3542"
|
|
||||||
cx="10.339486"
|
|
||||||
id="circle4483"
|
|
||||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
|
||||||
inkscape:export-filename=".\rect4485.png"
|
|
||||||
inkscape:export-xdpi="90"
|
|
||||||
inkscape:export-ydpi="90" />
|
|
||||||
<rect
|
|
||||||
inkscape:export-ydpi="90"
|
|
||||||
inkscape:export-xdpi="90"
|
|
||||||
inkscape:export-filename=".\rect4485.png"
|
|
||||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#000000;fill-opacity:0.32941176;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
|
||||||
id="rect4246"
|
|
||||||
width="3.6673687"
|
|
||||||
height="4.1063409"
|
|
||||||
x="14.115863"
|
|
||||||
y="1035.9174"
|
|
||||||
ry="0.72590536" />
|
|
||||||
<rect
|
|
||||||
ry="0.72590536"
|
|
||||||
y="1035.2253"
|
|
||||||
x="14.115863"
|
|
||||||
height="4.1063409"
|
|
||||||
width="3.6673687"
|
|
||||||
id="rect4485"
|
|
||||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#fffcfb;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
|
||||||
inkscape:export-filename=".\rect4485.png"
|
|
||||||
inkscape:export-xdpi="90"
|
|
||||||
inkscape:export-ydpi="90" />
|
|
||||||
<path
|
|
||||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#000000;fill-opacity:0.32941176;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
|
||||||
d="m 19.999735,1036.5289 c 0,0.838 -0.871228,1.2682 -2.144766,1.1659 -0.02366,0 -0.04795,-0.6004 -0.254147,-0.5832 -0.503669,0.042 -1.095902,-0.02 -1.685964,-0.02 -0.612939,0 -1.206342,0.1826 -1.68549,0.017 -0.110233,-0.038 -0.178298,0.5838 -0.261532,0.5816 -1.243685,-0.033 -2.078803,-0.3383 -2.078803,-1.1618 0,-1.2118 1.815635,-2.1941 4.055351,-2.1941 2.239704,0 4.055351,0.9823 4.055351,2.1941 z"
|
|
||||||
id="path4487"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
sodipodi:nodetypes="sssssssss"
|
|
||||||
inkscape:export-filename=".\rect4485.png"
|
|
||||||
inkscape:export-xdpi="90"
|
|
||||||
inkscape:export-ydpi="90" />
|
|
||||||
<path
|
|
||||||
sodipodi:nodetypes="sssssssss"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
id="path4489"
|
|
||||||
d="m 19.977414,1035.7004 c 0,0.5685 -0.433659,0.8554 -1.138091,1.0001 -0.291933,0.06 -0.630371,0.096 -1.003719,0.1166 -0.56405,0.032 -1.207782,0.031 -1.89122,0.031 -0.672834,0 -1.307182,0 -1.864904,-0.029 -0.306268,-0.017 -0.589429,-0.043 -0.843164,-0.084 -0.813833,-0.1318 -1.324962,-0.417 -1.324962,-1.0344 0,-1.1601 1.805642,-2.1006 4.03303,-2.1006 2.227377,0 4.03303,0.9405 4.03303,2.1006 z"
|
|
||||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#c38c74;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
|
||||||
inkscape:export-filename=".\rect4485.png"
|
|
||||||
inkscape:export-xdpi="90"
|
|
||||||
inkscape:export-ydpi="90" />
|
|
||||||
<ellipse
|
|
||||||
cy="1033.8501"
|
|
||||||
cx="15.944382"
|
|
||||||
id="ellipse4491"
|
|
||||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#23201f;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
|
||||||
rx="2.0801733"
|
|
||||||
ry="1.343747"
|
|
||||||
inkscape:export-filename=".\rect4485.png"
|
|
||||||
inkscape:export-xdpi="90"
|
|
||||||
inkscape:export-ydpi="90" />
|
|
||||||
<circle
|
|
||||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#171311;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
|
||||||
id="circle4493"
|
|
||||||
cx="12.414201"
|
|
||||||
cy="1030.3542"
|
|
||||||
r="1.9630634"
|
|
||||||
inkscape:export-filename=".\rect4485.png"
|
|
||||||
inkscape:export-xdpi="90"
|
|
||||||
inkscape:export-ydpi="90" />
|
|
||||||
<circle
|
|
||||||
r="1.9630634"
|
|
||||||
cy="1030.3542"
|
|
||||||
cx="23.110121"
|
|
||||||
id="circle4495"
|
|
||||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#171311;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
|
||||||
inkscape:export-filename=".\rect4485.png"
|
|
||||||
inkscape:export-xdpi="90"
|
|
||||||
inkscape:export-ydpi="90" />
|
|
||||||
<path
|
|
||||||
sodipodi:nodetypes="cc"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
id="path4497"
|
|
||||||
d="m 5.0055377,1027.2727 c -1.170435,-1.0835 -2.026973,-0.7721 -2.044172,-0.7463"
|
|
||||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#384e54;stroke-width:0.39730874;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
|
||||||
<path
|
|
||||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#384e54;stroke-width:0.39730874;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
|
||||||
d="m 4.3852457,1026.9152 c -1.158557,0.036 -1.346704,0.6303 -1.33881,0.6523"
|
|
||||||
id="path4499"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
sodipodi:nodetypes="cc" />
|
|
||||||
<path
|
|
||||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#384e54;stroke-width:0.39730874;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
|
||||||
d="m 26.630533,1027.1724 c 1.17043,-1.0835 2.02697,-0.7721 2.04417,-0.7463"
|
|
||||||
id="path4501"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
sodipodi:nodetypes="cc" />
|
|
||||||
<path
|
|
||||||
sodipodi:nodetypes="cc"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
id="path4503"
|
|
||||||
d="m 27.321773,1026.673 c 1.15856,0.036 1.3467,0.6302 1.3388,0.6522"
|
|
||||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#384e54;stroke-width:0.39730874;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
До Ширина: | Высота: | Размер: 17 KiB |
Двоичные данные
doc/gopher/fiveyears.jpg
До Ширина: | Высота: | Размер: 215 KiB |
Двоичные данные
doc/gopher/frontpage.png
До Ширина: | Высота: | Размер: 17 KiB |
Двоичные данные
doc/gopher/gopherbw.png
До Ширина: | Высота: | Размер: 167 KiB |
Двоичные данные
doc/gopher/gophercolor.png
До Ширина: | Высота: | Размер: 165 KiB |
Двоичные данные
doc/gopher/gophercolor16x16.png
До Ширина: | Высота: | Размер: 739 B |
Двоичные данные
doc/gopher/help.png
До Ширина: | Высота: | Размер: 5.6 KiB |
Двоичные данные
doc/gopher/modelsheet.jpg
До Ширина: | Высота: | Размер: 84 KiB |
Двоичные данные
doc/gopher/pencil/gopherhat.jpg
До Ширина: | Высота: | Размер: 127 KiB |
Двоичные данные
doc/gopher/pencil/gopherhelmet.jpg
До Ширина: | Высота: | Размер: 148 KiB |
Двоичные данные
doc/gopher/pencil/gophermega.jpg
До Ширина: | Высота: | Размер: 120 KiB |
Двоичные данные
doc/gopher/pencil/gopherrunning.jpg
До Ширина: | Высота: | Размер: 84 KiB |
Двоичные данные
doc/gopher/pencil/gopherswim.jpg
До Ширина: | Высота: | Размер: 155 KiB |
Двоичные данные
doc/gopher/pencil/gopherswrench.jpg
До Ширина: | Высота: | Размер: 226 KiB |
Двоичные данные
doc/gopher/pkg.png
До Ширина: | Высота: | Размер: 5.3 KiB |
Двоичные данные
doc/gopher/project.png
До Ширина: | Высота: | Размер: 7.9 KiB |
Двоичные данные
doc/gopher/ref.png
До Ширина: | Высота: | Размер: 5.8 KiB |
Двоичные данные
doc/gopher/run.png
До Ширина: | Высота: | Размер: 9.0 KiB |
Двоичные данные
doc/gopher/talks.png
До Ширина: | Высота: | Размер: 4.8 KiB |
|
@ -1,96 +0,0 @@
|
||||||
<!--{
|
|
||||||
"Title": "Help",
|
|
||||||
"Path": "/help/",
|
|
||||||
"Template": true
|
|
||||||
}-->
|
|
||||||
|
|
||||||
<div id="manual-nav"></div>
|
|
||||||
|
|
||||||
<h2 id="help">Get help</h2>
|
|
||||||
|
|
||||||
<img class="gopher" src="/doc/gopher/help.png" alt=""/>
|
|
||||||
|
|
||||||
{{if not $.GoogleCN}}
|
|
||||||
<h3 id="mailinglist"><a href="https://groups.google.com/group/golang-nuts">Go Nuts Mailing List</a></h3>
|
|
||||||
<p>
|
|
||||||
Get help from Go users, and share your work on the official mailing list.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
Search the <a href="https://groups.google.com/group/golang-nuts">golang-nuts</a>
|
|
||||||
archives and consult the <a href="/doc/go_faq.html">FAQ</a> and
|
|
||||||
<a href="//golang.org/wiki">wiki</a> before posting.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h3 id="forum"><a href="https://forum.golangbridge.org/">Go Forum</a></h3>
|
|
||||||
<p>
|
|
||||||
The <a href="https://forum.golangbridge.org/">Go Forum</a> is a discussion
|
|
||||||
forum for Go programmers.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h3 id="discord"><a href="https://discord.gg/64C346U">Gophers Discord</a></h3>
|
|
||||||
<p>
|
|
||||||
Get live support and talk with other gophers on the Go Discord.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h3 id="slack"><a href="https://blog.gopheracademy.com/gophers-slack-community/">Gopher Slack</a></h3>
|
|
||||||
<p>Get live support from other users in the Go slack channel.</p>
|
|
||||||
|
|
||||||
<h3 id="irc"><a href="irc:irc.freenode.net/go-nuts">Go IRC Channel</a></h3>
|
|
||||||
<p>Get live support at <b>#go-nuts</b> on <b>irc.freenode.net</b>, the official
|
|
||||||
Go IRC channel.</p>
|
|
||||||
{{end}}
|
|
||||||
|
|
||||||
<h3 id="faq"><a href="/doc/faq">Frequently Asked Questions (FAQ)</a></h3>
|
|
||||||
<p>Answers to common questions about Go.</p>
|
|
||||||
|
|
||||||
{{if not $.GoogleCN}}
|
|
||||||
<h2 id="inform">Stay informed</h2>
|
|
||||||
|
|
||||||
<h3 id="announce"><a href="https://groups.google.com/group/golang-announce">Go Announcements Mailing List</a></h3>
|
|
||||||
<p>
|
|
||||||
Subscribe to
|
|
||||||
<a href="https://groups.google.com/group/golang-announce">golang-announce</a>
|
|
||||||
for important announcements, such as the availability of new Go releases.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h3 id="blog"><a href="//blog.golang.org">Go Blog</a></h3>
|
|
||||||
<p>The Go project's official blog.</p>
|
|
||||||
|
|
||||||
<h3 id="twitter"><a href="https://twitter.com/golang">@golang at Twitter</a></h3>
|
|
||||||
<p>The Go project's official Twitter account.</p>
|
|
||||||
|
|
||||||
<h3 id="reddit"><a href="https://reddit.com/r/golang">golang sub-Reddit</a></h3>
|
|
||||||
<p>
|
|
||||||
The <a href="https://reddit.com/r/golang">golang sub-Reddit</a> is a place
|
|
||||||
for Go news and discussion.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h3 id="gotime"><a href="https://changelog.com/gotime">Go Time Podcast</a></h3>
|
|
||||||
<p>
|
|
||||||
The <a href="https://changelog.com/gotime">Go Time podcast</a> is a panel of Go experts and special guests
|
|
||||||
discussing the Go programming language, the community, and everything in between.
|
|
||||||
</p>
|
|
||||||
{{end}}
|
|
||||||
|
|
||||||
<h2 id="community">Community resources</h2>
|
|
||||||
|
|
||||||
<h3 id="go_user_groups"><a href="/wiki/GoUserGroups">Go User Groups</a></h3>
|
|
||||||
<p>
|
|
||||||
Each month in places around the world, groups of Go programmers ("gophers")
|
|
||||||
meet to talk about Go. Find a chapter near you.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
{{if not $.GoogleCN}}
|
|
||||||
<h3 id="playground"><a href="/play">Go Playground</a></h3>
|
|
||||||
<p>A place to write, run, and share Go code.</p>
|
|
||||||
|
|
||||||
<h3 id="wiki"><a href="/wiki">Go Wiki</a></h3>
|
|
||||||
<p>A wiki maintained by the Go community.</p>
|
|
||||||
{{end}}
|
|
||||||
|
|
||||||
<h3 id="conduct"><a href="/conduct">Code of Conduct</a></h3>
|
|
||||||
<p>
|
|
||||||
Guidelines for participating in Go community spaces
|
|
||||||
and a reporting process for handling issues.
|
|
||||||
</p>
|
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
#nav-main li { display: inline; }
|
|