Repository: superorbital/golangcookbook.github.io Branch: master Commit: 070bd68e4799 Files: 156 Total size: 104.5 KB Directory structure: gitextract_i_1wwnew/ ├── .gitignore ├── .prettierignore ├── .ruby-version ├── CNAME ├── Dockerfile ├── Gemfile ├── LICENSE.md ├── README.md ├── _config.yml ├── _data/ │ └── chapters.yml ├── _includes/ │ └── example.html ├── _layouts/ │ ├── default.html │ └── recipe.html ├── bin/ │ ├── server │ └── tests ├── chapters/ │ ├── arrays/ │ │ └── reverse/ │ │ ├── index.md │ │ ├── test_alternate.expected │ │ ├── test_alternate.expected.escaped │ │ ├── test_alternate.go │ │ ├── test_alternate.go.escaped │ │ ├── test_copy.expected │ │ ├── test_copy.expected.escaped │ │ ├── test_copy.go │ │ ├── test_copy.go.escaped │ │ ├── test_copy_simple.expected │ │ ├── test_copy_simple.expected.escaped │ │ ├── test_copy_simple.go │ │ ├── test_copy_simple.go.escaped │ │ ├── test_simple.expected │ │ ├── test_simple.expected.escaped │ │ ├── test_simple.go │ │ ├── test_simple.go.escaped │ │ ├── test_terse.expected │ │ ├── test_terse.expected.escaped │ │ ├── test_terse.go │ │ └── test_terse.go.escaped │ ├── files/ │ │ └── read-write/ │ │ └── index.md │ ├── maps/ │ │ └── presence/ │ │ └── index.md │ ├── numbers/ │ │ ├── enums/ │ │ │ └── index.md │ │ └── string_to_num/ │ │ ├── index.md │ │ ├── test_string_to_float.expected │ │ ├── test_string_to_float.expected.escaped │ │ ├── test_string_to_float.go │ │ ├── test_string_to_float.go.escaped │ │ ├── test_string_to_int.expected │ │ ├── test_string_to_int.expected.escaped │ │ ├── test_string_to_int.go │ │ └── test_string_to_int.go.escaped │ ├── running/ │ │ ├── cross-compiling/ │ │ │ └── index.md │ │ ├── one-off/ │ │ │ ├── index.md │ │ │ ├── test_empty.expected │ │ │ ├── test_empty.expected.escaped │ │ │ ├── test_empty.go │ │ │ ├── test_empty.go.escaped │ │ │ ├── test_hello_world.expected │ │ │ ├── test_hello_world.expected.escaped │ │ │ ├── test_hello_world.go │ │ │ └── test_hello_world.go.escaped │ │ └── shebang/ │ │ ├── bash.go │ │ ├── fail.go │ │ ├── gorun.go │ │ └── index.md │ └── strings/ │ ├── accessing/ │ │ ├── index.md │ │ ├── test_index.expected │ │ ├── test_index.expected.escaped │ │ ├── test_index.go │ │ └── test_index.go.escaped │ ├── concatenation/ │ │ └── index.md │ ├── detecting/ │ │ ├── index.md │ │ ├── test_precompiled_regexp.expected │ │ ├── test_precompiled_regexp.expected.escaped │ │ ├── test_precompiled_regexp.go │ │ ├── test_precompiled_regexp.go.escaped │ │ ├── test_regexp.expected │ │ ├── test_regexp.expected.escaped │ │ ├── test_regexp.go │ │ ├── test_regexp.go.escaped │ │ ├── test_returned_regexp.expected │ │ ├── test_returned_regexp.expected.escaped │ │ ├── test_returned_regexp.go │ │ ├── test_returned_regexp.go.escaped │ │ ├── test_safe_regexp.expected │ │ ├── test_safe_regexp.expected.escaped │ │ ├── test_safe_regexp.go │ │ ├── test_safe_regexp.go.escaped │ │ ├── test_substrings.expected │ │ ├── test_substrings.expected.escaped │ │ ├── test_substrings.go │ │ └── test_substrings.go.escaped │ ├── detecting-all/ │ │ └── index.md │ ├── processing/ │ │ ├── index.md │ │ ├── test_each_char.expected │ │ ├── test_each_char.expected.escaped │ │ ├── test_each_char.go │ │ ├── test_each_char.go.escaped │ │ ├── test_separator.expected │ │ ├── test_separator.expected.escaped │ │ ├── test_separator.go │ │ ├── test_separator.go.escaped │ │ ├── test_without_punctuation.expected │ │ ├── test_without_punctuation.expected.escaped │ │ ├── test_without_punctuation.go │ │ ├── test_without_punctuation.go.escaped │ │ ├── test_without_punctuation_using_map.expected │ │ ├── test_without_punctuation_using_map.expected.escaped │ │ ├── test_without_punctuation_using_map.go │ │ ├── test_without_punctuation_using_map.go.escaped │ │ ├── test_words.expected │ │ ├── test_words.expected.escaped │ │ ├── test_words.go │ │ └── test_words.go.escaped │ ├── processing-complex/ │ │ ├── index.md │ │ ├── test_regexp_match.expected │ │ ├── test_regexp_match.expected.escaped │ │ ├── test_regexp_match.go │ │ ├── test_regexp_match.go.escaped │ │ ├── test_regexp_separator.expected │ │ ├── test_regexp_separator.expected.escaped │ │ ├── test_regexp_separator.go │ │ └── test_regexp_separator.go.escaped │ ├── reverse/ │ │ ├── index.md │ │ ├── test_reverse_by_character.expected │ │ ├── test_reverse_by_character.expected.escaped │ │ ├── test_reverse_by_character.go │ │ ├── test_reverse_by_character.go.escaped │ │ ├── test_reverse_by_word.expected │ │ ├── test_reverse_by_word.expected.escaped │ │ ├── test_reverse_by_word.go │ │ └── test_reverse_by_word.go.escaped │ ├── sentence/ │ │ ├── index.md │ │ ├── test_join.expected │ │ ├── test_join.expected.escaped │ │ ├── test_join.go │ │ ├── test_join.go.escaped │ │ ├── test_sentence.expected │ │ ├── test_sentence.expected.escaped │ │ ├── test_sentence.go │ │ └── test_sentence.go.escaped │ ├── strings_suit_test.go │ ├── strings_test.go │ └── title/ │ ├── index.md │ ├── test_proper.expected │ ├── test_proper.expected.escaped │ ├── test_proper.go │ ├── test_proper.go.escaped │ ├── test_simple.expected │ ├── test_simple.expected.escaped │ ├── test_simple.go │ └── test_simple.go.escaped ├── index.md ├── params.json ├── run └── stylesheets/ ├── print.css ├── pygment_trac.css ├── site.scss └── stylesheet.css ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ _site test_output ================================================ FILE: .prettierignore ================================================ *.md ================================================ FILE: .ruby-version ================================================ 2.5.0 ================================================ FILE: CNAME ================================================ golangcookbook.com ================================================ FILE: Dockerfile ================================================ FROM ruby:2.5 RUN apt-get update \ && apt-get upgrade -y \ && apt-get install -y --no-install-recommends \ curl ENV GOROOT /usr/local/go ENV GOPATH /tmp/go ENV GOCACHE /tmp ENV GOVERSION 1.12.7 ENV PATH /site/bin:${GOROOT}/bin:${PATH} WORKDIR /usr/local RUN curl -sSL https://dl.google.com/go/go${GOVERSION}.linux-amd64.tar.gz | tar -zxf - RUN go version WORKDIR /site COPY Gemfile . COPY Gemfile.lock . RUN bundle install EXPOSE 8000 EXPOSE 8001 ENV PORT 8000 ENV LRPORT 8001 ENTRYPOINT ["/bin/bash"] ================================================ FILE: Gemfile ================================================ # A sample Gemfile source "https://rubygems.org" gem "github-pages" ================================================ FILE: LICENSE.md ================================================ ## creative commons # Attribution-NonCommercial-NoDerivatives 4.0 International Creative Commons Corporation (“Creative Commons”) is not a law firm and does not provide legal services or legal advice. Distribution of Creative Commons public licenses does not create a lawyer-client or other relationship. Creative Commons makes its licenses and related information available on an “as-is” basis. Creative Commons gives no warranties regarding its licenses, any material licensed under their terms and conditions, or any related information. Creative Commons disclaims all liability for damages resulting from their use to the fullest extent possible. ### Using Creative Commons Public Licenses Creative Commons public licenses provide a standard set of terms and conditions that creators and other rights holders may use to share original works of authorship and other material subject to copyright and certain other rights specified in the public license below. The following considerations are for informational purposes only, are not exhaustive, and do not form part of our licenses. * __Considerations for licensors:__ Our public licenses are intended for use by those authorized to give the public permission to use material in ways otherwise restricted by copyright and certain other rights. Our licenses are irrevocable. Licensors should read and understand the terms and conditions of the license they choose before applying it. Licensors should also secure all rights necessary before applying our licenses so that the public can reuse the material as expected. Licensors should clearly mark any material not subject to the license. This includes other CC-licensed material, or material used under an exception or limitation to copyright. [More considerations for licensors](http://wiki.creativecommons.org/Considerations_for_licensors_and_licensees#Considerations_for_licensors). * __Considerations for the public:__ By using one of our public licenses, a licensor grants the public permission to use the licensed material under specified terms and conditions. If the licensor’s permission is not necessary for any reason–for example, because of any applicable exception or limitation to copyright–then that use is not regulated by the license. Our licenses grant only permissions under copyright and certain other rights that a licensor has authority to grant. Use of the licensed material may still be restricted for other reasons, including because others have copyright or other rights in the material. A licensor may make special requests, such as asking that all changes be marked or described. Although not required by our licenses, you are encouraged to respect those requests where reasonable. [More considerations for the public](http://wiki.creativecommons.org/Considerations_for_licensors_and_licensees#Considerations_for_licensees). ## Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International Public License By exercising the Licensed Rights (defined below), You accept and agree to be bound by the terms and conditions of this Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International Public License ("Public License"). To the extent this Public License may be interpreted as a contract, You are granted the Licensed Rights in consideration of Your acceptance of these terms and conditions, and the Licensor grants You such rights in consideration of benefits the Licensor receives from making the Licensed Material available under these terms and conditions. ### Section 1 – Definitions. a. __Adapted Material__ means material subject to Copyright and Similar Rights that is derived from or based upon the Licensed Material and in which the Licensed Material is translated, altered, arranged, transformed, or otherwise modified in a manner requiring permission under the Copyright and Similar Rights held by the Licensor. For purposes of this Public License, where the Licensed Material is a musical work, performance, or sound recording, Adapted Material is always produced where the Licensed Material is synched in timed relation with a moving image. b. __Copyright and Similar Rights__ means copyright and/or similar rights closely related to copyright including, without limitation, performance, broadcast, sound recording, and Sui Generis Database Rights, without regard to how the rights are labeled or categorized. For purposes of this Public License, the rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights. e. __Effective Technological Measures__ means those measures that, in the absence of proper authority, may not be circumvented under laws fulfilling obligations under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996, and/or similar international agreements. f. __Exceptions and Limitations__ means fair use, fair dealing, and/or any other exception or limitation to Copyright and Similar Rights that applies to Your use of the Licensed Material. h. __Licensed Material__ means the artistic or literary work, database, or other material to which the Licensor applied this Public License. i. __Licensed Rights__ means the rights granted to You subject to the terms and conditions of this Public License, which are limited to all Copyright and Similar Rights that apply to Your use of the Licensed Material and that the Licensor has authority to license. h. __Licensor__ means the individual(s) or entity(ies) granting rights under this Public License. i. __NonCommercial__ means not primarily intended for or directed towards commercial advantage or monetary compensation. For purposes of this Public License, the exchange of the Licensed Material for other material subject to Copyright and Similar Rights by digital file-sharing or similar means is NonCommercial provided there is no payment of monetary compensation in connection with the exchange. j. __Share__ means to provide material to the public by any means or process that requires permission under the Licensed Rights, such as reproduction, public display, public performance, distribution, dissemination, communication, or importation, and to make material available to the public including in ways that members of the public may access the material from a place and at a time individually chosen by them. k. __Sui Generis Database Rights__ means rights other than copyright resulting from Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended and/or succeeded, as well as other essentially equivalent rights anywhere in the world. l. __You__ means the individual or entity exercising the Licensed Rights under this Public License. Your has a corresponding meaning. ### Section 2 – Scope. a. ___License grant.___ 1. Subject to the terms and conditions of this Public License, the Licensor hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive, irrevocable license to exercise the Licensed Rights in the Licensed Material to: A. reproduce and Share the Licensed Material, in whole or in part, for NonCommercial purposes only; and B. produce and reproduce, but not Share, Adapted Material for NonCommercial purposes only. 2. __Exceptions and Limitations.__ For the avoidance of doubt, where Exceptions and Limitations apply to Your use, this Public License does not apply, and You do not need to comply with its terms and conditions. 3. __Term.__ The term of this Public License is specified in Section 6(a). 4. __Media and formats; technical modifications allowed.__ The Licensor authorizes You to exercise the Licensed Rights in all media and formats whether now known or hereafter created, and to make technical modifications necessary to do so. The Licensor waives and/or agrees not to assert any right or authority to forbid You from making technical modifications necessary to exercise the Licensed Rights, including technical modifications necessary to circumvent Effective Technological Measures. For purposes of this Public License, simply making modifications authorized by this Section 2(a)(4) never produces Adapted Material. 5. __Downstream recipients.__ A. __Offer from the Licensor – Licensed Material.__ Every recipient of the Licensed Material automatically receives an offer from the Licensor to exercise the Licensed Rights under the terms and conditions of this Public License. B. __No downstream restrictions.__ You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, the Licensed Material if doing so restricts exercise of the Licensed Rights by any recipient of the Licensed Material. 6. __No endorsement.__ Nothing in this Public License constitutes or may be construed as permission to assert or imply that You are, or that Your use of the Licensed Material is, connected with, or sponsored, endorsed, or granted official status by, the Licensor or others designated to receive attribution as provided in Section 3(a)(1)(A)(i). ___Other rights.___ 1. Moral rights, such as the right of integrity, are not licensed under this Public License, nor are publicity, privacy, and/or other similar personality rights; however, to the extent possible, the Licensor waives and/or agrees not to assert any such rights held by the Licensor to the limited extent necessary to allow You to exercise the Licensed Rights, but not otherwise. 2. Patent and trademark rights are not licensed under this Public License. 3. To the extent possible, the Licensor waives any right to collect royalties from You for the exercise of the Licensed Rights, whether directly or through a collecting society under any voluntary or waivable statutory or compulsory licensing scheme. In all other cases the Licensor expressly reserves any right to collect such royalties, including when the Licensed Material is used other than for NonCommercial purposes. ### Section 3 – License Conditions. Your exercise of the Licensed Rights is expressly made subject to the following conditions. a. ___Attribution.___ 1. If You Share the Licensed Material, You must: A. retain the following if it is supplied by the Licensor with the Licensed Material: i. identification of the creator(s) of the Licensed Material and any others designated to receive attribution, in any reasonable manner requested by the Licensor (including by pseudonym if designated); ii. a copyright notice; iii. a notice that refers to this Public License; iv. a notice that refers to the disclaimer of warranties; v. a URI or hyperlink to the Licensed Material to the extent reasonably practicable; B. indicate if You modified the Licensed Material and retain an indication of any previous modifications; and C. indicate the Licensed Material is licensed under this Public License, and include the text of, or the URI or hyperlink to, this Public License. For the avoidance of doubt, You do not have permission under this Public License to Share Adapted Material. 2. You may satisfy the conditions in Section 3(a)(1) in any reasonable manner based on the medium, means, and context in which You Share the Licensed Material. For example, it may be reasonable to satisfy the conditions by providing a URI or hyperlink to a resource that includes the required information. 3. If requested by the Licensor, You must remove any of the information required by Section 3(a)(1)(A) to the extent reasonably practicable. ### Section 4 – Sui Generis Database Rights. Where the Licensed Rights include Sui Generis Database Rights that apply to Your use of the Licensed Material: a. for the avoidance of doubt, Section 2(a)(1) grants You the right to extract, reuse, reproduce, and Share all or a substantial portion of the contents of the database for NonCommercial purposes only and provided You do not Share Adapted Material; b. if You include all or a substantial portion of the database contents in a database in which You have Sui Generis Database Rights, then the database in which You have Sui Generis Database Rights (but not its individual contents) is Adapted Material; and c. You must comply with the conditions in Section 3(a) if You Share all or a substantial portion of the contents of the database. For the avoidance of doubt, this Section 4 supplements and does not replace Your obligations under this Public License where the Licensed Rights include other Copyright and Similar Rights. ### Section 5 – Disclaimer of Warranties and Limitation of Liability. a. __Unless otherwise separately undertaken by the Licensor, to the extent possible, the Licensor offers the Licensed Material as-is and as-available, and makes no representations or warranties of any kind concerning the Licensed Material, whether express, implied, statutory, or other. This includes, without limitation, warranties of title, merchantability, fitness for a particular purpose, non-infringement, absence of latent or other defects, accuracy, or the presence or absence of errors, whether or not known or discoverable. Where disclaimers of warranties are not allowed in full or in part, this disclaimer may not apply to You.__ b. __To the extent possible, in no event will the Licensor be liable to You on any legal theory (including, without limitation, negligence) or otherwise for any direct, special, indirect, incidental, consequential, punitive, exemplary, or other losses, costs, expenses, or damages arising out of this Public License or use of the Licensed Material, even if the Licensor has been advised of the possibility of such losses, costs, expenses, or damages. Where a limitation of liability is not allowed in full or in part, this limitation may not apply to You.__ c. The disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that, to the extent possible, most closely approximates an absolute disclaimer and waiver of all liability. ### Section 6 – Term and Termination. a. This Public License applies for the term of the Copyright and Similar Rights licensed here. However, if You fail to comply with this Public License, then Your rights under this Public License terminate automatically. b. Where Your right to use the Licensed Material has terminated under Section 6(a), it reinstates: 1. automatically as of the date the violation is cured, provided it is cured within 30 days of Your discovery of the violation; or 2. upon express reinstatement by the Licensor. For the avoidance of doubt, this Section 6(b) does not affect any right the Licensor may have to seek remedies for Your violations of this Public License. c. For the avoidance of doubt, the Licensor may also offer the Licensed Material under separate terms or conditions or stop distributing the Licensed Material at any time; however, doing so will not terminate this Public License. d. Sections 1, 5, 6, 7, and 8 survive termination of this Public License. ### Section 7 – Other Terms and Conditions. a. The Licensor shall not be bound by any additional or different terms or conditions communicated by You unless expressly agreed. b. Any arrangements, understandings, or agreements regarding the Licensed Material not stated herein are separate from and independent of the terms and conditions of this Public License. ### Section 8 – Interpretation. a. For the avoidance of doubt, this Public License does not, and shall not be interpreted to, reduce, limit, restrict, or impose conditions on any use of the Licensed Material that could lawfully be made without permission under this Public License. b. To the extent possible, if any provision of this Public License is deemed unenforceable, it shall be automatically reformed to the minimum extent necessary to make it enforceable. If the provision cannot be reformed, it shall be severed from this Public License without affecting the enforceability of the remaining terms and conditions. c. No term or condition of this Public License will be waived and no failure to comply consented to unless expressly agreed to by the Licensor. d. Nothing in this Public License constitutes or may be interpreted as a limitation upon, or waiver of, any privileges and immunities that apply to the Licensor or You, including from the legal processes of any jurisdiction or authority. > Creative Commons is not a party to its public licenses. Notwithstanding, Creative Commons may elect to apply one of its public licenses to material it publishes and in those instances will be considered the “Licensor.” Except for the limited purpose of indicating that material is shared under a Creative Commons public license or as otherwise permitted by the Creative Commons policies published at [creativecommons.org/policies](http://creativecommons.org/policies), Creative Commons does not authorize the use of the trademark “Creative Commons” or any other trademark or logo of Creative Commons without its prior written consent including, without limitation, in connection with any unauthorized modifications to any of its public licenses or any other arrangements, understandings, or agreements concerning use of licensed material. For the avoidance of doubt, this paragraph does not form part of the public licenses. > > Creative Commons may be contacted at creativecommons.org ================================================ FILE: README.md ================================================ # Go Cookbook Source for [the Go Cookbook](http://golangcookbook.com), a community built collection of practical recipes and contributions for real world Golang development, supported by [SuperOrbital](https://superorbit.al). ### Contributing The Go Cookbook is supported by [SuperOrbital](https://superorbit.al), but built by the community, so your contributions are very welcome. Just send a pull request for any changes or additions. #### Adding a New Recipe Recipes are generated from the [_data/chapters.yml file](https://github.com/golangcookbook/golangcookbook.github.io/blob/master/_data/chapters.yml), which is used to build [the index page](https://github.com/golangcookbook/golangcookbook.github.io/blob/master/index.md). The `chapters.yml` file format is: ``` - title: Strings recipes: - title: Concatenating Strings path: /chapters/strings/concatenation wip: true - title: Detecting a Substring path: /chapters/strings/detecting - title: Detecting All Substrings path: false ``` Specifying `wip: true` puts "[Work in progress]" in front of the recipe in the index. Setting `path: false` causes the recipe to be listed without a link. #### Recipe Format Recipe files have a couple of required properties, specified in the preamble like such: ``` yaml --- title: Processing a String One Word or Character at a Time question: Given a string, how do I break it into words or characters and process each one in turn? --- ``` Also, to show example code, recipes can make use of the `{% include example.html example="filename" %}` helper. This will include both `filename.go` as example source code, and `filename.expected.escaped` as the output of that code. If you're curious, [here's the definition for that helper](https://github.com/golangcookbook/golangcookbook.github.io/blob/master/_includes/example.html). The `filename.expected.escaped` files are automatically generated by the `./run_tests` script, described below. ### Run locally This project uses Docker for local development. Once you have Docker installed: ``` console $ ./run server $ open http://localhost:4000 ``` ### Run the tests ``` console $ ./run tests ``` The `run_tests` script runs the tests and ensures the `.expected`, `.go.escaped`, and `.expected.escaped` files are in place. These files are used in the recipe templates to ensure all examples are up to date and correct. ### License [](http://creativecommons.org/licenses/by-nc-sa/4.0/) The Go Cookbook copyright [SuperOrbital](https://superorbit.al), and is licensed under a [Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License](http://creativecommons.org/licenses/by-nc-sa/4.0/). ================================================ FILE: _config.yml ================================================ name: The Go Cookbook markdown: kramdown kramdown: input: GFM sass: style: :compressed defaults: - scope: path: "chapters" values: layout: recipe ================================================ FILE: _data/chapters.yml ================================================ - title: Running & Packaging recipes: - title: Running a One-Off File path: /chapters/running/one-off - title: Cross Compiling path: /chapters/running/cross-compiling - title: Building a binary path: false - title: Running a file via a shebang line path: /chapters/running/shebang - title: Exploring Go with a REPL path: false - title: Managing dependencies path: false - title: Strings recipes: - title: Concatenating Strings path: /chapters/strings/concatenation wip: true - title: Detecting a Substring path: /chapters/strings/detecting wip: true - title: Detecting All Substrings path: /chapters/strings/detecting-all wip: true - title: Accessing Substrings path: /chapters/strings/accessing wip: true - title: Processing a String One Word or Character at a Time path: /chapters/strings/processing - title: Processing a String by Complex Separators and Patterns path: /chapters/strings/processing-complex - title: Reversing a String by Word or Character path: /chapters/strings/reverse - title: Replacing Parts of a String path: false - title: Expanding and Compressing Tabs path: false - title: Expanding Variables in User Input path: false - title: Interpolating Functions and Expressions Within Strings path: false - title: Indenting Here Documents path: false - title: Escaping Characters path: false - title: Trimming Blanks from the Ends of a String path: false - title: Controlling Case path: false - title: Properly Capitalizing a Title path: /chapters/strings/title - title: Turning an Array into a Sentence path: /chapters/strings/sentence - title: Parsing Comma-Separated Data path: false - title: Numbers recipes: - title: Representing Enums in Go path: /chapters/numbers/enums wip: true - title: Checking Whether a String Is a Valid Number path: /chapters/numbers/string_to_num wip: true - title: Rounding Floating-Point Numbers path: false - title: Comparing Floating-Point Numbers path: false - title: Operating on a Series of Integers path: false - title: Working with Roman Numerals path: false - title: Generating Random Numbers path: false - title: Generating Repeatable Random Number Sequences path: false - title: Making Numbers Even More Random path: false - title: Generating Biased Random Numbers path: false - title: Doing Trigonometry in Degrees, Not Radians path: false - title: Calculating More Trigonometric Functions path: false - title: Taking Logarithms path: false - title: Multiplying Matrices path: false - title: Using Complex Numbers path: false - title: Converting Binary, Octal, and Hexadecimal Numbers path: false - title: Putting Commas in Numbers path: false - title: Printing Correct Plurals path: false - title: Dates and Times recipes: - title: Finding Today's Date path: false - title: Converting DMYHMS to Epoch Seconds path: false - title: Converting Epoch Seconds to DMYHMS path: false - title: Adding to or Subtracting from a Date path: false - title: Difference of Two Dates path: false - title: Day in a Week/Month/Year or Week Number path: false - title: Parsing Dates and Times from Strings path: false - title: Printing a Date path: false - title: High-Resolution Timers path: false - title: Short Sleeps path: false - title: Arrays recipes: - title: Specifying a List in Your Program path: false - title: Printing a List with Commas path: false - title: Changing Array Size path: false - title: Implementing a Sparse Array path: false - title: Iterating Over an Array path: false - title: Iterating Over an Array by Reference path: false - title: Extracting Unique Elements from a List path: false - title: Finding Elements in One Array but Not Another path: false - title: Computing Union, Intersection, or Difference of Unique Lists path: false - title: Appending One Array to Another path: false - title: Reversing an Array path: /chapters/arrays/reverse - title: Processing Multiple Elements of an Array path: false - title: Finding the First List Element That Passes a Test path: false - title: Finding All Elements in an Array Matching Certain Criteria path: false - title: Sorting an Array Numerically path: false - title: Sorting a List by Computable Field path: false - title: Implementing a Circular List path: false - title: Randomizing an Array path: false - title: Maps recipes: - title: Adding an Element to a Map path: false - title: Testing for the Presence of a Key in a Map path: /chapters/maps/presence wip: true - title: Deleting from a Map path: false - title: Traversing a Map path: false - title: Convert a Map into an Array of keys or values path: false source: "http://stackoverflow.com/a/27398024" - title: Printing a Map path: false - title: Mapes with Multiple Values per Key path: false - title: Inverting a Map path: false - title: Sorting a Map path: false - title: Merging Maps path: false - title: Finding Common or Different Keys in Two Maps path: false - title: Files recipes: - title: Checking the Existence of a File source: "http://stackoverflow.com/a/12518877/2620448" - title: Reading and Writing to Files path: /chapters/files/read-write - title: Expanding Tildes in Filenames path: false - title: Creating Temporary Files path: false - title: Storing a File Inside Your Program Text path: false - title: Storing Multiple Files in the DATA Area path: false - title: Writing a Unix-Style Filter Program path: false - title: Modifying a File in Place with a Temporary File path: false - title: Modifying a File in Place with the -i Switch path: false - title: Modifying a File in Place Without a Temporary File path: false - title: Locking a File path: false - title: Flushing Output path: false - title: Doing Non-Blocking I/O path: false - title: Determining the Number of Unread Bytes path: false - title: Reading from Many Filehandles Without Blocking path: false - title: Reading an Entire Line Without Blocking path: false - title: Counting Lines (or Paragraphs or Records) in a File path: false - title: Processing Every Word in a File path: false - title: Reading a File Backward by Line or Paragraph path: false - title: Trailing a Growing File path: false - title: Picking a Random Line from a File path: false - title: Randomizing All Lines path: false - title: Reading a Particular Line in a File path: false - title: Processing Variable-Length Text Fields path: false - title: Removing the Last Line of a File path: false - title: Processing Binary Files path: false - title: Using Random-Access I/O path: false - title: Updating a Random-Access File path: false - title: Reading a String from a Binary File path: false - title: Reading Fixed-Length Records path: false - title: Reading Configuration Files path: false - title: Testing a File for Trustworthiness path: false - title: Reading or Writing Unicode from a Filehandle path: false - title: Comparing the Contents of Two Files path: false - title: Reading and writing JSON files path: false source: "http://golang.org/pkg/encoding/json/#example_Decoder" - title: Reading and writing YAML files path: false - title: Directories recipes: - title: Getting and Setting Timestamps path: false - title: Deleting a File path: false - title: Copying or Moving a File path: false - title: Recognizing Two Names for the Same File path: false - title: Processing All Files in a Directory path: false - title: Globbing, or Getting a List of Filenames Matching a Pattern path: false - title: Processing All Files in a Directory Recursively path: false source: "http://stackoverflow.com/a/6612243/2620448" - title: Removing a Directory and Its Contents path: false - title: Renaming Files path: false - title: Splitting a Filename into Its Component Parts path: false - title: Working with Symbolic File Permissions Instead of Octal Values path: false - title: Goroutines - title: Systems Programming recipes: - title: Catching signals source: "http://stackoverflow.com/a/11269077/2620448" - title: Running Child Processes source: "http://stackoverflow.com/a/14885714/2620448" - title: Processing Command-line Arguments source: "https://golang.org/pkg/flag/" - title: Sockets recipes: - title: Writing a TCP Client path: false - title: Writing a TCP Server path: false - title: Communicating over TCP path: false - title: Setting Up a UDP Client path: false - title: Setting Up a UDP Server path: false - title: Using Unix Domain Sockets path: false - title: Identifying the Other End of a Socket path: false - title: Finding Your Own Name and Address path: false - title: Closing a Socket After Forking path: false - title: Writing Bidirectional Clients path: false - title: Forking Servers path: false - title: Pre-Forking Servers path: false - title: Non-Forking Servers path: false - title: Multitasking Server with Threads path: false - title: Writing a Multitasking Server with POE path: false - title: Writing a Multihomed Server path: false - title: Making a Daemon Server path: false - title: Restarting a Server on Demand path: false - title: Managing Multiple Streams of Input path: false - title: Internet Services recipes: - title: Simple DNS Lookups path: false source: "http://golang.org/pkg/net/#LookupHost and http://miek.nl/posts/2014/Aug/16/go-dns-package/" - title: Sending Mail path: false source: "https://code.google.com/p/go-wiki/wiki/SendingMail" - title: Reading and Posting Usenet News Messages path: false - title: Reading Mail with POP3 path: false - title: Simulating Telnet from a Program path: false - title: Pinging a Machine path: false - title: Accessing an LDAP Server path: false - title: Sending Attachments in Mail path: false - title: Extracting Attachments from Mail path: false - title: Writing a RESTful service path: false - title: Connecting to MySQL path: false source: "http://stackoverflow.com/questions/11353679/whats-the-recommended-way-to-connect-to-mysql-from-go" - title: Connecting to PgSQL source: "http://www.alexedwards.net/blog/practical-persistence-sql" - title: Fetching a URL path: false - title: Setting HTTP Headers path: false - title: Automating Form Submission path: false - title: Extracting URLs path: false - title: Converting ASCII to HTML path: false - title: Converting HTML to ASCII path: false - title: Extracting or Removing HTML Tags path: false - title: Finding Stale Links path: false - title: Finding Fresh Links path: false - title: Using Templates to Generate HTML path: false - title: Mirroring Web Pages path: false - title: Creating a Robot path: false - title: Parsing a Web Server Log File path: false - title: Processing Server Logs path: false - title: Using Cookies path: false - title: Fetching Password-Protected Pages path: false - title: Fetching https:// Web Pages path: false - title: Resuming an HTTP GET path: false - title: Parsing HTML path: false - title: Extracting Table Data path: false - title: Processing POST requests source: "http://stackoverflow.com/questions/15672556/handling-json-post-request-in-go" ================================================ FILE: _includes/example.html ================================================
{% include_relative test_{{ include.example }}.go.escaped %}
$ go run test_{{include.example}}.go
{% include_relative test_{{ include.example }}.expected.escaped %}
{{ page.question }}
{{ content }} ================================================ FILE: bin/server ================================================ #!/usr/bin/env bash set -eou pipefail bundle exec jekyll serve -H 0.0.0.0 -wDP "$PORT" -l --livereload-port "$LRPORT" -t ================================================ FILE: bin/tests ================================================ #!/usr/bin/env bash TEST_OUTPUT=/tmp/test_output.$$ print_success() { echo -n .; } print_failure() { echo -n x; } print_pending() { echo -n p; } print_output() { echo; cat $TEST_OUTPUT/*; } run_test() { diff <( go run "$1" 2>&1) "$2" > /dev/null; } record_failure() { { echo "Failed: $1" echo " To reset, run:" echo " rm $2" diff -yW200 <( go run "$1" 2>&1) "$2" echo "------------------------" echo } >> "$TEST_OUTPUT/${1//\//_}.out" } generate_expected() { echo echo "$2 not found - generating it..." go run "$1" > "$2" } generate_escaped() { sed 's/&(?!amp;)/\&/g; s/\</g; s/>/\>/g; s/"/\"/g; s/'"'"'/\'/g' < "$1" > "$1.escaped" } process_file() { file=$1 expected=${file/.go/.expected} if [ -s "$file" ]; then if [ -f "$expected" ]; then if run_test "$file" "$expected"; then print_success else record_failure "$file" "$expected" print_failure fi else generate_expected "$file" "$expected" fi else print_pending fi generate_escaped "$expected" generate_escaped "$file" } main() { mkdir $TEST_OUTPUT touch $TEST_OUTPUT/cat_on_empty_dir_hangs if [[ "$#" -gt 0 ]]; then shopt -s nullglob files=( "$@" ) else readarray -t files < <(find chapters -name "test*.go") fi echo "Running tests for ${files[*]}" for file in "${files[@]}"; do process_file "$file" & done wait print_output rm -rf $TEST_OUTPUT } main "$@" ================================================ FILE: chapters/arrays/reverse/index.md ================================================ --- title: Reversing an Array question: How do I reverse an array? --- Reversing an array is fairly straightforward in Go, due to multiple return values. Simply loop through the first half of the array, swapping each element in turn with its mirror counterpart: {%include example.html example="simple"%} There's an even more terse implementation which makes use of the `,` operator inside the Go for loop: {%include example.html example="terse"%} Note that both of these `reverse` functions take slices, which are passed by value. This is good for performance, but means we're actually modifying the passed in array, leading to unexpected results. In other words, the `reverse` method could be written like such: {%include example.html example="alternate"%} Now `reverse` doesn't return another reference to the slice, which makes it much more clear that it's modifying the slice in-place. If we want to return a modified copy of the slice, we must do so manually: {%include example.html example="copy"%} As you can see in the output above, the original array is untouched. Since we're not modifying the array in-place, we can also simplify our algorithm buy doing a more straight-forward element copy: {%include example.html example="copy_simple"%} ================================================ FILE: chapters/arrays/reverse/test_alternate.expected ================================================ [5 4 3 2 1] ================================================ FILE: chapters/arrays/reverse/test_alternate.expected.escaped ================================================ [5 4 3 2 1] ================================================ FILE: chapters/arrays/reverse/test_alternate.go ================================================ package main import "fmt" func reverse(numbers []int) { for i, j := 0, len(numbers)-1; i < j; i, j = i+1, j-1 { numbers[i], numbers[j] = numbers[j], numbers[i] } } func main() { array := []int{1, 2, 3, 4, 5} reverse(array) fmt.Printf("%v\n", array) } ================================================ FILE: chapters/arrays/reverse/test_alternate.go.escaped ================================================ package main import "fmt" func reverse(numbers []int) { for i, j := 0, len(numbers)-1; i < j; i, j = i+1, j-1 { numbers[i], numbers[j] = numbers[j], numbers[i] } } func main() { array := []int{1, 2, 3, 4, 5} reverse(array) fmt.Printf("%v\n", array) } ================================================ FILE: chapters/arrays/reverse/test_copy.expected ================================================ [5 4 3 2 1] [1 2 3 4 5] ================================================ FILE: chapters/arrays/reverse/test_copy.expected.escaped ================================================ [5 4 3 2 1] [1 2 3 4 5] ================================================ FILE: chapters/arrays/reverse/test_copy.go ================================================ package main import "fmt" func reverse(numbers []int) []int { newNumbers := make([]int, len(numbers)) for i, j := 0, len(numbers)-1; i <= j; i, j = i+1, j-1 { newNumbers[i], newNumbers[j] = numbers[j], numbers[i] } return newNumbers } func main() { array := []int{1, 2, 3, 4, 5} fmt.Printf("%v\n", reverse(array)) fmt.Printf("%v\n", array) } ================================================ FILE: chapters/arrays/reverse/test_copy.go.escaped ================================================ package main import "fmt" func reverse(numbers []int) []int { newNumbers := make([]int, len(numbers)) for i, j := 0, len(numbers)-1; i <= j; i, j = i+1, j-1 { newNumbers[i], newNumbers[j] = numbers[j], numbers[i] } return newNumbers } func main() { array := []int{1, 2, 3, 4, 5} fmt.Printf("%v\n", reverse(array)) fmt.Printf("%v\n", array) } ================================================ FILE: chapters/arrays/reverse/test_copy_simple.expected ================================================ [5 4 3 2 1] [1 2 3 4 5] ================================================ FILE: chapters/arrays/reverse/test_copy_simple.expected.escaped ================================================ [5 4 3 2 1] [1 2 3 4 5] ================================================ FILE: chapters/arrays/reverse/test_copy_simple.go ================================================ package main import "fmt" func reverse(numbers []int) []int { newNumbers := make([]int, 0, len(numbers)) for i := len(numbers)-1; i >= 0; i-- { newNumbers = append(newNumbers, numbers[i]) } return newNumbers } func main() { array := []int{1, 2, 3, 4, 5} fmt.Printf("%v\n", reverse(array)) fmt.Printf("%v\n", array) } ================================================ FILE: chapters/arrays/reverse/test_copy_simple.go.escaped ================================================ package main import "fmt" func reverse(numbers []int) []int { newNumbers := make([]int, 0, len(numbers)) for i := len(numbers)-1; i >= 0; i-- { newNumbers = append(newNumbers, numbers[i]) } return newNumbers } func main() { array := []int{1, 2, 3, 4, 5} fmt.Printf("%v\n", reverse(array)) fmt.Printf("%v\n", array) } ================================================ FILE: chapters/arrays/reverse/test_simple.expected ================================================ [5 4 3 2 1] [4 3 2 1] ================================================ FILE: chapters/arrays/reverse/test_simple.expected.escaped ================================================ [5 4 3 2 1] [4 3 2 1] ================================================ FILE: chapters/arrays/reverse/test_simple.go ================================================ package main import "fmt" func reverse(numbers []int) []int { for i := 0; i < len(numbers)/2; i++ { j := len(numbers) - i - 1 numbers[i], numbers[j] = numbers[j], numbers[i] } return numbers } func main() { fmt.Printf("%v\n", reverse([]int{1, 2, 3, 4, 5})) fmt.Printf("%v\n", reverse([]int{1, 2, 3, 4})) } ================================================ FILE: chapters/arrays/reverse/test_simple.go.escaped ================================================ package main import "fmt" func reverse(numbers []int) []int { for i := 0; i < len(numbers)/2; i++ { j := len(numbers) - i - 1 numbers[i], numbers[j] = numbers[j], numbers[i] } return numbers } func main() { fmt.Printf("%v\n", reverse([]int{1, 2, 3, 4, 5})) fmt.Printf("%v\n", reverse([]int{1, 2, 3, 4})) } ================================================ FILE: chapters/arrays/reverse/test_terse.expected ================================================ [5 4 3 2 1] [4 3 2 1] ================================================ FILE: chapters/arrays/reverse/test_terse.expected.escaped ================================================ [5 4 3 2 1] [4 3 2 1] ================================================ FILE: chapters/arrays/reverse/test_terse.go ================================================ package main import "fmt" func reverse(numbers []int) []int { for i, j := 0, len(numbers)-1; i < j; i, j = i+1, j-1 { numbers[i], numbers[j] = numbers[j], numbers[i] } return numbers } func main() { fmt.Printf("%v\n", reverse([]int{1, 2, 3, 4, 5})) fmt.Printf("%v\n", reverse([]int{1, 2, 3, 4})) } ================================================ FILE: chapters/arrays/reverse/test_terse.go.escaped ================================================ package main import "fmt" func reverse(numbers []int) []int { for i, j := 0, len(numbers)-1; i < j; i, j = i+1, j-1 { numbers[i], numbers[j] = numbers[j], numbers[i] } return numbers } func main() { fmt.Printf("%v\n", reverse([]int{1, 2, 3, 4, 5})) fmt.Printf("%v\n", reverse([]int{1, 2, 3, 4})) } ================================================ FILE: chapters/files/read-write/index.md ================================================ --- title: Reading and Writing to Files question: How do I read from and write to a file? --- http://stackoverflow.com/questions/1821811/how-to-read-write-from-to-file http://stackoverflow.com/a/16615559/2620448 ================================================ FILE: chapters/maps/presence/index.md ================================================ --- title: Testing for the Presence of a Key in a Map question: How do I determine if a map contains a given key? --- http://stackoverflow.com/questions/2050391/how-to-check-if-a-map-contains-a-key-in-go ================================================ FILE: chapters/numbers/enums/index.md ================================================ --- title: Representing Enums question: How do I represent enumerated constants in Go? --- http://stackoverflow.com/questions/14426366/what-is-an-idiomatic-way-of-representing-enums-in-golang http://stackoverflow.com/a/1721367 ================================================ FILE: chapters/numbers/string_to_num/index.md ================================================ --- title: Converting a string to number question: How do I convert a string to number if possible in Go? --- Go comes with a core package called `strconv` which makes this task very easy. You can convert a string to an integer and specify a base as well. You also have the flexibility to define the size of bits into which the number should fit into. {% include example.html example="string_to_int" %} The `strconv` package also contains functions such as `ParseUint` and `ParseFloat` which convert a string to unsigned integer and floating point numbers respectively. {% include example.html example="string_to_float" %} ================================================ FILE: chapters/numbers/string_to_num/test_string_to_float.expected ================================================ float64 123.123000 ================================================ FILE: chapters/numbers/string_to_num/test_string_to_float.expected.escaped ================================================ float64 123.123000 ================================================ FILE: chapters/numbers/string_to_num/test_string_to_float.go ================================================ package main import ( "fmt" "os" "strconv" ) func main() { str := "123.123" /* The first argument to ParseInt is the string to be converted. The second argument is the number of bits to which the number should fit. */ i, err := strconv.ParseFloat(str, 64) if err != nil { fmt.Println(err) os.Exit(1) } fmt.Printf("%T %f\n", i, i) } ================================================ FILE: chapters/numbers/string_to_num/test_string_to_float.go.escaped ================================================ package main import ( "fmt" "os" "strconv" ) func main() { str := "123.123" /* The first argument to ParseInt is the string to be converted. The second argument is the number of bits to which the number should fit. */ i, err := strconv.ParseFloat(str, 64) if err != nil { fmt.Println(err) os.Exit(1) } fmt.Printf("%T %f\n", i, i) } ================================================ FILE: chapters/numbers/string_to_num/test_string_to_int.expected ================================================ int64 123 strconv.ParseInt: parsing "invalidString123": invalid syntax ================================================ FILE: chapters/numbers/string_to_num/test_string_to_int.expected.escaped ================================================ int64 123 strconv.ParseInt: parsing "invalidString123": invalid syntax ================================================ FILE: chapters/numbers/string_to_num/test_string_to_int.go ================================================ package main import ( "fmt" "strconv" ) func handleError(err error) { if err != nil { fmt.Println(err) } } func main() { str := "123" /* The first argument to ParseInt is the string to be converted. The second argument is the base to which the number is to be converted. The third argument is the number of bits to which the number should fit. */ i, err := strconv.ParseInt(str, 10, 64) handleError(err) fmt.Printf("%T %d\n", i, i) str = "invalidString123" _, err = strconv.ParseInt(str, 10, 64) handleError(err) } ================================================ FILE: chapters/numbers/string_to_num/test_string_to_int.go.escaped ================================================ package main import ( "fmt" "strconv" ) func handleError(err error) { if err != nil { fmt.Println(err) } } func main() { str := "123" /* The first argument to ParseInt is the string to be converted. The second argument is the base to which the number is to be converted. The third argument is the number of bits to which the number should fit. */ i, err := strconv.ParseInt(str, 10, 64) handleError(err) fmt.Printf("%T %d\n", i, i) str = "invalidString123" _, err = strconv.ParseInt(str, 10, 64) handleError(err) } ================================================ FILE: chapters/running/cross-compiling/index.md ================================================ --- title: Cross Compiling question: How do I compile a binary designed to run on a different platform than my local host? --- Since Go is a statically compiled language, it's well designed for producing tiny, pre-compiled tools. This is great for Unix administrators or DevOps engineers, as they can send their tools with them when they work on remote systems. However, many developers use OS X or Windows on their local machine, and another OS like Linux on others. How do you use one system to compile binaries that will work on the other? This is called cross-compiling, and it's pretty simple with Go. ### Pre 1.5 Before 1.5, cross compilation was an arduous process, requiring [massive scripts](http://dave.cheney.net/2013/07/09/an-introduction-to-cross-compilation-with-go-1-1) to build separate go compilers for each supported platform. ### Post 1.5 Things have been much better since v1.5 of Go was released. Go now [comes with support for all architectures built in](http://dave.cheney.net/2015/03/03/cross-compilation-just-got-a-whole-lot-better-in-go-1-5). That means cross compiling is as simple as setting the right `$GOOS` and `$GOARCH` environment variables before building. Consider the below example program, which simply prints the OS and Architecture it's compiled for. While the output will always be the same as the platform it's being executed on, it's really a compile-time value - not something determined at runtime. ``` package main import "fmt" import "runtime" func main() { fmt.Printf("OS: %s\nArchitecture: %s\n", runtime.GOOS, runtime.GOARCH) } ``` Now, let's compile this program for an Apple MacBook. To do so, we simply set two environment variables: `$GOOS`, which is the target operating system, and `$GOARCH`, which is the target processor. Then we run `go build` as normal: ``` $ GOOS=darwin GOARCH=386 go build test.go ``` Note that the `test` executable that comes out the other end only runs on OS X, and cannot be run on Linux or Windows. On the other hand, if we wanted to compile for Microsoft Windows, we'd simply set `GOOS=windows` and `GOARCH=386`. When we run the resulting binary on the right platform, we see: ``` $ ./test OS: windows Architecture: 386 ``` This is another example of Go's strengths as a language for building easily distributed tools. It's almost trivial to modify your build process to produce binaries for every major platform your users may run. This is used, for example, to enable the Cloud Foundry team to distribute [Linux, Windows, and OS X CLI tools](https://github.com/cloudfoundry/cli). ================================================ FILE: chapters/running/one-off/index.md ================================================ --- title: Running a one-off File question: What's the easiest way to run a single Go file? --- First steps are often both fundamental and overlooked. Go's unusual packaging and compilation process can be daunting and confusing to a new developer. Unlike most compiled languages, Go actually comes with a very easy way of running a single file. Simply execute the program with `go run filename.go`: {% include example.html example="hello_world" %} This allows Go to act as though it were a more dynamic language, and is useful for development and exploration. However, Go's compiler is so incredibly fast, that it's possible to use this technique in a production setting: ``` $ time go run empty.go real 0m0.103s user 0m0.058s sys 0m0.033s ``` Throughout this book, you'll see many Go programs. Each one is available as a separate file in this book, and each example includes the `go run` command required to run the file along side the full output. ================================================ FILE: chapters/running/one-off/test_empty.expected ================================================ ================================================ FILE: chapters/running/one-off/test_empty.expected.escaped ================================================ ================================================ FILE: chapters/running/one-off/test_empty.go ================================================ package main func main() { } ================================================ FILE: chapters/running/one-off/test_empty.go.escaped ================================================ package main func main() { } ================================================ FILE: chapters/running/one-off/test_hello_world.expected ================================================ Hello World! ================================================ FILE: chapters/running/one-off/test_hello_world.expected.escaped ================================================ Hello World! ================================================ FILE: chapters/running/one-off/test_hello_world.go ================================================ package main import "fmt" func main() { fmt.Println("Hello World!") } ================================================ FILE: chapters/running/one-off/test_hello_world.go.escaped ================================================ package main import "fmt" func main() { fmt.Println("Hello World!") } ================================================ FILE: chapters/running/shebang/bash.go ================================================ //usr/bin/env go run $0 $@; exit package main func main() { println("hello") } ================================================ FILE: chapters/running/shebang/fail.go ================================================ #!/usr/bin/env go run package main func main() { println("hello") } ================================================ FILE: chapters/running/shebang/gorun.go ================================================ #!/usr/bin/env gorun package main func main() { println("hello") } ================================================ FILE: chapters/running/shebang/index.md ================================================ --- title: Running a file via a shebang line question: How can I add a shebang line to the top of my Go file in order to run it directly, as though it were an interpreted script? --- ### "Shebang??" In order to make it possible to execute scripts as though they were first class executables, UNIX systems will looks for what we refer to as a shebang line at the top of the file. The origin of the name is murky. Some think it came from sharp-bang or hash-bang -- contractions of `#` ("sharp") and `!` ("bang"). Others think the "SH" is in reference to the first UNIX shell, named "sh". In any case, if a UNIX system sees that the first line of an executable begins with `#!`, then it will execute the file using whatever command is specified in the rest of the line. For example, if there's a file named `/path/to/bar` that looks like: ``` #!/bin/foo ... ``` Then, when run, the kernel will execute `/bin/foo /path/to/bar`. This is great for interpreted languages like Ruby and Python which allow `#` as an innocuous comment. A clever gopher might attempt to create a file named `/path/to/example` that looks like such: ``` golang #!/usr/local/bin/go run package main import "fmt" func main() { fmt.Println("Hello!") } ``` And expect to run it and see "hello" in their terminal. However, Go does not allow `#` as a comment, which causes this to fail with a syntax error: ``` $ ./fail.go fail.go:1:1: illegal character U+0023 '#' ``` In order for this to work, the Go spec would have to be modified to accept `#` as a comment on the first line of the file. However, the Go authors are highly opinionated. When (repeatedly) asked for this feature, [Rob Pike has said](https://groups.google.com/d/msg/golang-nuts/iGHWoUQFHjg/_dbLKomrPmUJ): > I have never said it cannot be done. I have always said it should not be done, and I have explained why. > > "Useful" is not an argument for a feature. All features are useful; otherwise they would not be features. The issue is whether the feature justifies its cost. That is a judgement call, and my judgement is, no. Running compilers and linkers, doing megabytes of I/O, and creating temporary binary files is not a justifiable expense for running a small program. For large programs, the amortization is even more in favor of not doing this. > > I am firmly against adding a feature to Go that encourages abuse of resources. > > If you want the feature, use gorun or an equivalent wrapper program. That's what it's for. I think believe [sic] gorun is a mistake, but I'm not stopping you from installing it and using it as you see fit. ### gorun What's this gorun that has Rob up in arms? The Ubuntu Linux distribution produced the [gorun utility](https://wiki.ubuntu.com/gorun) to solve the shebang issue. As listed in the homepage, gorun will: * write files under a safe directory in `$TMPDIR` (or `/tmp`), so that the actual script location isn't touched (may be read-only) * avoid races between parallel executions of the same file * automatically clean up old compiled files that remain unused for some time (without races) * replace the process rather than using a child * pass arguments to the compiled application properly * handle well `GOROOT`, `GOROOT_FINAL` and the location of the toolchain Importantly, gorun will also strip the shebang line from the executed file before running it via `go run`. Because gorun is a separate tool, and not included in the Go distribution, it must first be installed via `go get launchpad.net/gorun`. Once it's installed, you can make use of it quite simply: ``` #!/usr/bin/gorun package main func main() { println("Hello world!") } ``` This file is now executable on the command line (after setting the execution bit via `chmod +x`, of course). However, it's also technically invalid Go. This means you can't compile the same code via `go build` that you would run with gorun. As we said earlier, this solution also requires that your users install gorun, making it less portable than ideal. As of March 1st, 2015, [gorun does not compile on OS X](https://bugs.launchpad.net/gorun/+bug/1176275), but it looks like this will be resolved, soon. {:.warning} ### Mimic the shebang via Bash In UNIX systems, the shebang line is handled by the family of `exec` functions inside the fundamental libc. The `exec` functions use what's referred to as magic numbers in the first bits of a file to determine what kind of executable it is. The characters `#!` are simply hard coded as a magic number that corresponds to being run as a script. But we can make clever use of the fact that `//` is both a comment in Go, *and* interpreted as a valid part of a file path in Bash, in order to trick Bash into running the file for us instead of `exec`. This isn't technically a shebang line, but serves the same purpose quite nicely. The resulting file looks like such: ``` //usr/bin/go run $0 $@; exit $? package main func main() { println("Hello world!") } ``` This file is *both* a valid Bash script and valid Go source code. When Bash runs this file, it executes `/usr/bin/go run $0 $@`, and then immediately exits. If the file were named "/path/to/foo.go", and we ran it like `./foo.go bar baz`, then Bash would execute `/usr/bin/go run ./foo.go "bar" "baz"`. At this point, the file is parsed by `go run`, which ignores the first line as a comment, and dutifully compiles and executes the rest of the file. This trick doesn't require a separately installed command, and is relatively portable. However, all is not roses: * The file must end in `.go`, since `go run` will happily ignore it otherwise. * This only works when executed via a shell. It won't work if executed directly by other programs. ### Trade-offs Sadly, unless Rob changes his mind and modifies the Go spec, there is no one-size-fits-all solution in sight. Both of the recipes above have their drawbacks, and choosing which one to use is entirely about your specific needs and tastes. ================================================ FILE: chapters/strings/accessing/index.md ================================================ --- title: Accessing Substrings question: How do I access parts of a given string? --- Go allows you to access parts of a string via the normal indexing primitives you're accustomed to using with arrays and slices. In particular, it allows you to access `mystring[n:m]`. Either `n` or `m` can be omitted, which implies from the beginning or to the end, respectively. There's also the primitive `len(s)`, which gives you the number of characters in the string. Here are some examples: {% include example.html example="index" %} Accessing strings by character, word or token are covered in the [Processing a String One Word or Character at a Time](/chapters/strings/processing) recipe. ================================================ FILE: chapters/strings/accessing/test_index.expected ================================================ Hello Hello ello World World ello Worl ================================================ FILE: chapters/strings/accessing/test_index.expected.escaped ================================================ Hello Hello ello World World ello Worl ================================================ FILE: chapters/strings/accessing/test_index.go ================================================ package main import "fmt" func main() { s := "Hello World" fmt.Println(s[:5]) // the first 5 characters fmt.Println(s[:len(s)-6]) // the same, but counting back from the end fmt.Println(s[1:]) // all except the first character fmt.Println(s[len(s)-5:]) // the last 5 characters fmt.Println(s[1 : len(s)-1]) // all except the first and last } ================================================ FILE: chapters/strings/accessing/test_index.go.escaped ================================================ package main import "fmt" func main() { s := "Hello World" fmt.Println(s[:5]) // the first 5 characters fmt.Println(s[:len(s)-6]) // the same, but counting back from the end fmt.Println(s[1:]) // all except the first character fmt.Println(s[len(s)-5:]) // the last 5 characters fmt.Println(s[1 : len(s)-1]) // all except the first and last } ================================================ FILE: chapters/strings/concatenation/index.md ================================================ --- title: Concatenating Strings question: How do I combine strings? --- http://stackoverflow.com/questions/1760757/how-to-efficiently-concatenate-strings-in-go http://srcode.org/2014/08/23/string-concatenation-in-golang/ ================================================ FILE: chapters/strings/detecting/index.md ================================================ --- title: Detecting a Substring question: How do I determine if a string contains another string or pattern? --- Go prides itself on being a low level language with a rich set of functionality included by default via the standard packages. The `strings` package is a great example of this. ### Detecting Substrings * `strings.Contains` * `strings.ContainsAny` * `strings.HasPrefix` * `strings.HasSuffix` {% include example.html example="substrings" %} ### Detecting Patterns {% include example.html example="regexp" %} ### Finding Matched Strings {% include example.html example="returned_regexp" %} ### Detecting Patterns that Include Special Characters {% include example.html example="safe_regexp" %} ### Precompiling Regular Expressions * `regexp.Compile` * `regexp.MustCompile` {% include example.html example="precompiled_regexp" %} ================================================ FILE: chapters/strings/detecting/test_precompiled_regexp.expected ================================================ ================================================ FILE: chapters/strings/detecting/test_precompiled_regexp.expected.escaped ================================================ ================================================ FILE: chapters/strings/detecting/test_precompiled_regexp.go ================================================ package main import "fmt" func main() { fmt.Println("unimplemented") } ================================================ FILE: chapters/strings/detecting/test_precompiled_regexp.go.escaped ================================================ package main import "fmt" func main() { fmt.Println("unimplemented") } ================================================ FILE: chapters/strings/detecting/test_regexp.expected ================================================ Matched: true Error: