Learning Go by comparing how you'd do it in Python

Top Hello World 🔗 Python print ( "Hello world" ) Go package main import "fmt" func main () { fmt . Println ( "Hello world" ) }

Top Print 🔗 Python print ( "Some string" ) print ( "Some string" , end = "" ) # no newline character printed print ( "Name: {}, Age: {}" . format ( "Peter" , 35 )) Go package main import "fmt" func main () { fmt . Println ( "Some string" ) fmt . Print ( "Some string" ) fmt . Printf ( "Name: %s, Age: %d

" , "Peter" , 35 ) }

Top Comments 🔗 Python """This is a doc string for the whole module""" # This is a inline comment class Class ( object ): """This is the doc string for the class""" print ( __doc__ ) print ( Class . __doc__ ) Go package main // This is a general comment /* This is also a comment but on multiple lines. */ /* This is the multi-line comment for the function main(). To get access to this from the command line, run: godoc comments.go */ func main () { }

Top Multiline Strings 🔗 Python print ( """This is a multi-line string. """ ) print ( "O'word " 'Another "word" ' "Last word." ) Go package main import "fmt" func main () { fmt . Println ( `This is a multi-line string. ` ) fmt . Println ( "O'word " + "Another \"word\" " + "Last word." ) }

Top Lists 🔗 A slice is a segment of an array whose length can change. The major difference between an array and a slice is that with the array you need to know the size up front. In Go, there is no way to equally easily add values to an existing slice so if you want to easily add values, you can initialize a slice at a max length and incrementally add things to it. Python # initialize list numbers = [ 0 ] * 5 # change one of them numbers [ 2 ] = 100 some_numbers = numbers [ 1 : 3 ] print ( some_numbers ) # [0, 100] # length of it print ( len ( numbers )) # 5 # initialize another scores = [] scores . append ( 1.1 ) scores [ 0 ] = 2.2 print ( scores ) # [2.2] Go package main import "fmt" func main () { // initialized array var numbers [ 5 ] int // becomes [0, 0, 0, 0, 0] // change one of them numbers [ 2 ] = 100 // create a new slice from an array some_numbers := numbers [ 1 : 3 ] fmt . Println ( some_numbers ) // [0, 100] // length of it fmt . Println ( len ( numbers )) // initialize a slice var scores [] float64 scores = append ( scores , 1.1 ) // recreate to append scores [ 0 ] = 2.2 // change your mind fmt . Println ( scores ) // prints [2.2] // when you don't know for sure how much you're going // to put in it, one way is to var things [ 100 ] string things [ 0 ] = "Peter" things [ 1 ] = "Anders" fmt . Println ( len ( things )) // 100 }

Top Maps 🔗 You can make a map of maps with: elements : make ( map [ string ] map [ string ] int ) elements [ "H" ] = map [ string ] int { "protons" : 1 , "neutrons" : 0 , } But note, this is what you have struct for. Python elements = {} elements [ "H" ] = 1 print ( elements [ "H" ]) # 1 # remove by key elements [ "O" ] = 8 elements . pop ( "O" ) # do something depending on the being there if "O" in elements : print ( elements [ "O" ]) if "H" in elements : print ( elements [ "H" ]) Go package main import "fmt" func main () { elements := make ( map [ string ] int ) elements [ "H" ] = 1 fmt . Println ( elements [ "H" ]) // remove by key elements [ "O" ] = 8 delete ( elements , "O" ) // only do something with a element if it's in the map if number , ok := elements [ "O" ]; ok { fmt . Println ( number ) // won't be printed } if number , ok := elements [ "H" ]; ok { fmt . Println ( number ) // 1 } }

Top Booleans 🔗 Go doesn't have a quick way to evaluate if something is "truthy". In Python, for example, you can use an if statement on any type and most types have a way of automatically converting to True or False . For example you can do: x = 1 if x : print "Yes" y = [] if y : print "this won't be printed" This is not possible in Go. You really need to do it explicitly for every type: x := 1 if x != 0 { fmt . Println ( "Yes" ) } var y [] string if len ( y ) != 0 { fmt . Println ( "this won't be printed" ) } Python print ( True and False ) # False print ( True or False ) # True print ( not True ) # False Go package main import "fmt" func main () { fmt . Println ( true && false ) // false fmt . Println ( true || false ) // true fmt . Println (! true ) // false x := 1 if x != 0 { fmt . Println ( "Yes" ) } var y [] string if len ( y ) != 0 { fmt . Println ( "this won't be printed" ) } }

Top Forloop 🔗 Go has only one type of loop and that's the for loop. Python i = 1 while i <= 10 : print ( i ) i += 1 # ...or... for i in range ( 1 , 11 ): print ( i ) Go package main import "fmt" func main () { i := 1 for i <= 10 { fmt . Println ( i ) i += 1 } // same thing more but more convenient for i := 1 ; i <= 10 ; i ++ { fmt . Println ( i ) } }

Top Range 🔗 Python names = [ "Peter" , "Anders" , "Bengt" ] for i , name in enumerate ( names ): print ( "{}. {}" . format ( i + 1 , name )) Go package main import "fmt" func main () { names := [] string { "Peter" , "Anders" , "Bengt" , } /* This will print 1. Peter 2. Anders 3. Bengt */ for i , name := range names { fmt . Printf ( "%d. %s

" , i + 1 , name ) } }

Top Switch 🔗 Python def input_ (): return int ( input ()) number = input_ () if number == 8 : print ( "Oxygen" ) elif number == 1 : print ( "Hydrogen" ) elif number == 2 : print ( "Helium" ) elif number == 11 : print ( "Sodium" ) else : print ( "I have no idea what %d is" % number ) # Alternative solution number = input_ () db = { 1 : "Hydrogen" , 2 : "Helium" , 8 : "Oxygen" , 11 : "Sodium" } print ( db . get ( number , "I have no idea what %d is" % number )) Go package main import ( "fmt" "strconv" ) func str2int ( s string ) int { i , err := strconv . Atoi ( s ) if err != nil { panic ( "Not a number" ) } return i } func main () { var number_string string fmt . Scanln ( & number_string ) number := str2int ( number_string ) switch number { case 8 : fmt . Println ( "Oxygen" ) case 1 : fmt . Println ( "Hydrogen" ) case 2 : fmt . Println ( "Helium" ) case 11 : fmt . Println ( "Sodium" ) default : fmt . Printf ( "I have no idea what %d is

" , number ) } // Alternative solution fmt . Scanln ( & number_string ) db := map [ int ] string { 1 : "Hydrogen" , 2 : "Helium" , 8 : "Oxygen" , 11 : "Sodium" , } number = str2int ( number_string ) if name , exists := db [ number ]; exists { fmt . Println ( name ) } else { fmt . Printf ( "I have no idea what %d is

" , number ) } }

Top Variadic Functions 🔗 In Python you can accept varying types with somefunction(*args) but this is not possible with Go. You can however, make the type an interface thus being able to get much more rich type structs. Python def average ( * numbers ): return sum ( numbers ) / len ( numbers ) print ( average ( 1 , 2 , 3 , 4 )) # 10/4 = 2.5 Go package main import "fmt" func average ( numbers ... float64 ) float64 { total := 0.0 for _ , number := range numbers { total += number } return total / float64 ( len ( numbers )) } func main () { fmt . Println ( average ( 1 , 2 , 3 , 4 )) // 2.5 }

Top Time Elapsed 🔗 Python import time t0 = time . time () time . sleep ( 3.5 ) # for example t1 = time . time () print ( "Took {:.2f} seconds" . format ( t1 - t0 )) Go package main import "fmt" import "time" func main () { t0 := time . Now () elapsed := time . Since ( t0 ) fmt . Printf ( "Took %s" , elapsed ) }

Top Closure Functions 🔗 Note in the Python example you can access number in the inner function but you can't change it. Suppose you wanted to do this: def increment ( amount ): number += amount increment ( 1 ) increment ( 2 ) Then you would get a UnboundLocalError error because the variable would be tied to the inner scope of the increment function. Note: you can use the global statement, to get around that, example def increment ( amount ): global number number += amount increment ( 1 ) increment ( 2 ) Python def run (): def increment ( amount ): return number + amount number = 0 number = increment ( 1 ) number = increment ( 2 ) print ( number ) # 3 run () Go package main import "fmt" func main () { number := 0 /* It has to be a local variable like this. You can't do `func increment(amount int) {` */ increment := func ( amount int ) { number += amount } increment ( 1 ) increment ( 2 ) fmt . Println ( number ) // 3 }

Top Defer 🔗 The cool thing about defer in Go is that you can type that near where it matters and it's then clear to the reader that it will do that later. In Python you can sort of achive the same thing by keeping the content between the try: and the finally: block short. Python f = open ( "defer.py" ) try : f . read () finally : f . close () Go package main import ( "os" ) func main () { f , _ := os . Open ( "defer.py" ) defer f . Close () // you can now read from this // `f` thing and it'll be closed later }

Top Panic Recover 🔗 Python try : raise Exception ( "Shit" ) except Exception as e : print ( "error was:" , e ) Go package main import "fmt" func main () { // Running this will print out: // error was: Shit! defer func () { fmt . Println ( "error was:" , recover ()) }() panic ( "Shit!" ) }

Top Mutables 🔗 Python doesn't have the concept of pointers. Go does. But with Go you can send an array or a map into a function, have it modified there without being returned and it gets changed. Python def upone ( mutable , index ): mutable [ index ] = mutable [ index ] . upper () list_ = [ "a" , "b" , "c" ] upone ( list_ , 1 ) print ( list_ ) # ['a', 'B', 'c'] dict_ = { "a" : "anders" , "b" : "bengt" } upone ( dict_ , "b" ) print ( dict_ ) # {'a': 'anders', 'b': 'BENGT'} Go package main import ( "fmt" "strings" ) func upone_list ( thing [] string , index int ) { thing [ index ] = strings . ToUpper ( thing [ index ]) } func upone_map ( thing map [ string ] string , index string ) { thing [ index ] = strings . ToUpper ( thing [ index ]) } func main () { // mutable list := [] string { "a" , "b" , "c" } upone_list ( list , 1 ) fmt . Println ( list ) // [a B c] // mutable dict := map [ string ] string { "a" : "anders" , "b" : "bengt" , } upone_map ( dict , "b" ) fmt . Println ( dict ) // map[a:anders b:BENGT] }

Top Structs 🔗 Python from math import sqrt class Point ( object ): def __init__ ( self , x , y ): self . x = x self . y = y def distance ( point1 , point2 ): return sqrt ( point1 . x * point2 . x + point1 . y * point2 . y ) p1 = Point ( 1 , 3 ) p2 = Point ( 2 , 4 ) print ( distance ( p1 , p2 )) # 3.74165738677 Go package main import ( "fmt" "math" ) type Point struct { x float64 y float64 } func distance ( point1 Point , point2 Point ) float64 { return math . Sqrt ( point1 . x * point2 . x + point1 . y * point2 . y ) } // Since structs get automatically copied, // it's better to pass it as pointer. func distance_better ( point1 * Point , point2 * Point ) float64 { return math . Sqrt ( point1 . x * point2 . x + point1 . y * point2 . y ) } func main () { p1 := Point { 1 , 3 } p2 := Point { 2 , 4 } fmt . Println ( distance ( p1 , p2 )) // 3.7416573867739413 fmt . Println ( distance_better ( & p1 , & p2 )) // 3.7416573867739413 }

Top Methods 🔗 Python from math import sqrt class Point ( object ): def __init__ ( self , x , y ): self . x = x self . y = y def distance ( self , other ): return sqrt ( self . x * other . x + self . y * other . y ) p1 = Point ( 1 , 3 ) p2 = Point ( 2 , 4 ) print ( p1 . distance ( p2 )) # 3.74165738677 print ( p2 . distance ( p1 )) # 3.74165738677 Go package main import ( "fmt" "math" ) type Point struct { x float64 y float64 } func ( this Point ) distance ( other Point ) float64 { return math . Sqrt ( this . x * other . x + this . y * other . y ) } // Dince structs get automatically copied, // it's better to pass it as pointer. func ( this * Point ) distance_better ( other * Point ) float64 { return math . Sqrt ( this . x * other . x + this . y * other . y ) } func main () { p1 := Point { 1 , 3 } p2 := Point { 2 , 4 } fmt . Println ( p1 . distance ( p2 )) // 3.7416573867739413 fmt . Println ( p1 . distance_better ( & p2 )) // 3.7416573867739413 }

Top Goroutines 🔗 Note that when you run these, the numbers come in in different order between runs. In the Python example, it exits automatically when all requests have finished. Python import urllib2 import multiprocessing def f ( url ): req = urllib2 . urlopen ( url ) try : print ( len ( req . read ())) finally : req . close () urls = ( "https://www.peterbe.com" , "https://python.org" , "https://golang.org" ) if __name__ == "__main__" : p = multiprocessing . Pool ( 3 ) p . map ( f , urls ) Go package main import ( "fmt" "io/ioutil" "net/http" "sync" ) func f ( url string ) { response , err := http . Get ( url ) if err != nil { panic ( err ) } defer response . Body . Close () body , err := ioutil . ReadAll ( response . Body ) if err != nil { panic ( err ) } fmt . Println ( len ( body )) } // See the example in https://golang.org/pkg/sync/#WaitGroup func main () { var wg sync . WaitGroup urls := [] string { "https://www.peterbe.com" , "https://python.org" , "https://golang.org" , } for _ , url := range urls { wg . Add ( 1 ) go func ( url string ) { defer wg . Done () f ( url ) }( url ) } // Wait for the goroutines to finish wg . Wait () }

Top Markdownserver 🔗 Using simple ab (with concurrency): $ ab -n 10000 -c 10 http://localhost:XXXX/markdown?body=THis+%2Ais%2A+a+string Where XXXX is the port number depending on which server you're running. Results: Python (Flask) 2103.06 [#/sec] (mean) Python (Tornado) 1834.48 [#/sec] (mean) Node (Express) 4406.17 [#/sec] (mean) Go 19539.61 [#/sec] (mean) To run the Go version, first set your $GOPATH then: $ go get github.com/russross/blackfriday $ go run main.go $ curl http://localhost:8080/markdown?body=THis+%2Ais%2A+a+string To run the Tornado versions: $ virtualenv venv $ source venv/bin/activate $ pip install tornado mistune markdown $ python tornado_.py $ curl http://localhost:8888/markdown?body=THis+%2Ais%2A+a+string To run the Flask version: $ virtualenv venv $ source venv/bin/activate $ pip install Flask mistune markdown $ python flask_.py $ curl http://localhost:5000/markdown?body=THis+%2Ais%2A+a+string To run the NodeJS version: $ npm install # picks up from package.json $ node node_.js $ curl http://localhost:3000/markdown?body=THis+%2Ais%2A+a+string Python try : import mistune as markdown except ImportError : import markdown # py implementation import tornado.ioloop import tornado.web class MarkdownHandler ( tornado . web . RequestHandler ): def get ( self ): body = self . get_argument ( "body" ) self . write ( markdown . markdown ( body )) application = tornado . web . Application ([( r "/markdown" , MarkdownHandler )]) if __name__ == "__main__" : application . listen ( 8888 ) tornado . ioloop . IOLoop . instance () . start () import logging try : import mistune as markdown except ImportError : import markdown # py implementation from flask import Flask , request app = Flask ( __name__ ) log = logging . getLogger ( "werkzeug" ) log . setLevel ( logging . ERROR ) @app.route ( "/markdown" ) def markdown_view (): return markdown . markdown ( request . args [ "body" ]) if __name__ == "__main__" : app . run () Go package main import ( "net/http" "os" "github.com/russross/blackfriday" ) func main () { port := os . Getenv ( "PORT" ) if port == "" { port = "8080" } http . HandleFunc ( "/markdown" , GenerateMarkdown ) http . ListenAndServe ( ":" + port , nil ) } func GenerateMarkdown ( rw http . ResponseWriter , r * http . Request ) { markdown := blackfriday . MarkdownCommon ( [] byte ( r . FormValue ( "body" ))) rw . Write ( markdown ) }

Top ORM (Object Relational Mapper) 🔗 This is a comparison between gorp and sqlalchemy. Using pq and psycopg2 it creates a bunch of ORM instance objects, then edits them all one by one and then deletes them all. This example assumes PostgreSQL and that the table already exists. It creates X number of "talks" which has the following column types: id serial integer topic varchar(200) when timestamp tags array of text duration real Then lastly it measures how long it takes to do all the inserts, all the updates and all the deletes. When running these for 10,000 iterations on my computer I get the following outputs: $ python orm.py insert 3.09894585609 edit 30.3197979927 delete 18.6974749565 TOTAL 52.1162188053 $ go run orm.go insert 2.542336905s edit 10.28062312s delete 6.851942699s TOTAL 19.674902724s Python # *- coding: utf-8 -* import time import random import datetime from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import Column , Integer , String , Float , DateTime , Sequence from sqlalchemy.dialects import postgresql HOW_MANY = 1000 # import logging # logging.basicConfig() # logger = logging.getLogger('sqlalchemy.engine') # logger.setLevel(logging.INFO) Base = declarative_base () class Talk ( Base ): __tablename__ = "talks" id = Column ( Integer , Sequence ( "talks_id_seq" ), primary_key = True ) topic = Column ( String ) when = Column ( DateTime ) tags = Column ( postgresql . ARRAY ( String )) duration = Column ( Float ) def _random_topic (): return random . choice ( ( "No talks added yet" , "I'm working on a branch of django-mongokit that I " "thought you'd like to know about." , "I want to learn Gaelic." , "I'm well, thank you." , " (Kaw uhn KEU-ra shin KAW-la root uh CHOO-nik mee uhn-royer?)" , "Chah beh shin KEU-ra, sheh shin moe CHYEH-luh uh vah EEN-tchuh!" , "STUH LUH-oom BRISS-kaht-chun goo MAWR" , "Suas Leis a' Ghàidhlig! Up with Gaelic!" , "Tha mi ag iarraidh briosgaid!" , ) ) def _random_when (): return datetime . datetime ( random . randint ( 2000 , 2010 ), random . randint ( 1 , 12 ), random . randint ( 1 , 28 ), 0 , 0 , 0 , ) def _random_tags (): tags = [ "one" , "two" , "three" , "four" , "five" , "six" , "seven" , "eight" , "nine" , "ten" , ] random . shuffle ( tags ) return tags [: random . randint ( 0 , 3 )] def _random_duration (): return round ( random . random () * 10 , 1 ) def run (): engine = create_engine ( "postgresql://peterbe:test123@localhost/fastestdb" , echo = False ) Session = sessionmaker ( bind = engine ) session = Session () session . query ( Talk ) . delete () t0 = time . time () # CREATE ALL talks = [] for i in range ( HOW_MANY ): talk = Talk ( topic = _random_topic (), when = _random_when (), duration = _random_duration (), tags = _random_tags (), ) session . add ( talk ) talks . append ( talk ) session . commit () t1 = time . time () # EDIT ALL for talk in talks : talk . topic += "extra" talk . duration += 1.0 talk . when += datetime . timedelta ( days = 1 ) talk . tags . append ( "extra" ) session . merge ( talk ) session . commit () t2 = time . time () # DELETE EACH for talk in talks : session . delete ( talk ) session . commit () t3 = time . time () print ( "insert" , t1 - t0 ) print ( "edit" , t2 - t1 ) print ( "delete" , t3 - t2 ) print ( "TOTAL" , t3 - t0 ) if __name__ == "__main__" : run () Go package main import ( "database/sql" "errors" "fmt" "github.com/coopernurse/gorp" _ "github.com/lib/pq" "log" "math/rand" // "os" "regexp" "strings" "time" ) type StringSlice [] string // Implements sql.Scanner for the String slice type // Scanners take the database value (in this case as a byte slice) // and sets the value of the type. Here we cast to a string and // do a regexp based parse func ( s * StringSlice ) Scan ( src interface {}) error { asBytes , ok := src .([] byte ) if ! ok { return error ( errors . New ( "Scan source was not []bytes" )) } asString := string ( asBytes ) parsed := parseArray ( asString ) ( * s ) = StringSlice ( parsed ) return nil } func ToArray ( str [] string ) string { L := len ( str ) out := "{" for i , s := range str { out += "\"" + s + "\"" if i + 1 < L { out += "," } } out += "}" return out } // construct a regexp to extract values: var ( // unquoted array values must not contain: (" , \ { } whitespace NULL) // and must be at least one char unquotedChar = `[^",\\{}\s(NULL)]` unquotedValue = fmt . Sprintf ( "(%s)+" , unquotedChar ) // quoted array values are surrounded by double quotes, can be any // character except " or \, which must be backslash escaped: quotedChar = `[^"\\]|\\"|\\\\` quotedValue = fmt . Sprintf ( "\"(%s)*\"" , quotedChar ) // an array value may be either quoted or unquoted: arrayValue = fmt . Sprintf ( "(?P<value>(%s|%s))" , unquotedValue , quotedValue ) // Array values are separated with a comma IF there is more than one value: arrayExp = regexp . MustCompile ( fmt . Sprintf ( "((%s)(,)?)" , arrayValue )) valueIndex int ) // Find the index of the 'value' named expression func init () { for i , subexp := range arrayExp . SubexpNames () { if subexp == "value" { valueIndex = i break } } } // Parse the output string from the array type. // Regex used: (((?P<value>(([^",\\{}\s(NULL)])+|"([^"\\]|\\"|\\\\)*")))(,)?) func parseArray ( array string ) [] string { results := make ([] string , 0 ) matches := arrayExp . FindAllStringSubmatch ( array , - 1 ) for _ , match := range matches { s := match [ valueIndex ] // the string _might_ be wrapped in quotes, so trim them: s = strings . Trim ( s , "\"" ) results = append ( results , s ) } return results } const HOW_MANY = 1000 func random_topic () string { topics := [] string { "No talks added yet" , "I'm working on a branch of django-mongokit that I thought you'd like to know about." , "I want to learn Gaelic." , "I'm well, thank you." , "(Kaw uhn KEU-ra shin KAW-la root uh CHOO-nik mee uhn-royer?)" , "Chah beh shin KEU-ra, sheh shin moe CHYEH-luh uh vah EEN-tchuh!" , "STUH LUH-oom BRISS-kaht-chun goo MAWR" , "Suas Leis a' Ghàidhlig! Up with Gaelic!" , "Tha mi ag iarraidh briosgaid!" , } return topics [ rand . Intn ( len ( topics ))] } func random_when () time . Time { return time . Date ( 2000 + rand . Intn ( 10 ), time . November , rand . Intn ( 12 ), rand . Intn ( 28 ), 0 , 0 , 0 , time . UTC ) } func random_tags () [] string { tags := [] string { "one" , "two" , "three" , "four" , "five" , "six" , "seven" , "eight" , "nine" , "ten" , } return tags [: rand . Intn ( 4 )] } func random_duration () float64 { return rand . Float64 () * 10 } func main () { dbmap := initDb () defer dbmap . Db . Close () // alter sequence talks_id_seq restart with 1; err := dbmap . TruncateTables () checkErr ( err , "TruncateTables failed" ) // dbmap.TraceOn("[gorp]", log.New(os.Stdout, "myapp:", log.Lmicroseconds)) t0 := time . Now () var talks [ HOW_MANY ] Talk trans , err := dbmap . Begin () if err != nil { panic ( err ) } // CREATE for i := 0 ; i < HOW_MANY ; i ++ { topic := random_topic () when := random_when () tags := random_tags () duration := random_duration () talk := Talk { Topic : topic , When : when , Tags : ToArray ( tags ), Duration : duration , } err = dbmap . Insert ( & talk ) checkErr ( err , "Insert failed" ) talks [ i ] = talk } trans . Commit () t1 := time . Since ( t0 ) t0 = time . Now () trans , err = dbmap . Begin () if err != nil { panic ( err ) } // EDIT ALL for _ , talk := range talks { talk . Topic += "extra" talk . Duration += 1.0 talk . When = talk . When . Add ( time . Hour * 24 ) tags := parseArray ( talk . Tags ) talk . Tags = ToArray ( append ( tags , "extra" )) _ , err := dbmap . Update ( & talk ) checkErr ( err , "Update failed" ) } trans . Commit () t2 := time . Since ( t0 ) t0 = time . Now () trans , err = dbmap . Begin () if err != nil { panic ( err ) } // DELETE ALL for _ , talk := range talks { _ , err = dbmap . Exec ( "delete from talks where id=$1" , talk . Id ) checkErr ( err , "Delete failed" ) } trans . Commit () t3 := time . Since ( t0 ) fmt . Println ( "insert" , t1 ) fmt . Println ( "edit" , t2 ) fmt . Println ( "delete" , t3 ) fmt . Println ( "TOTAL" , t1 + t2 + t3 ) } type Talk struct { // db tag lets you specify the column name // if it differs from the struct field Id int64 `db:"id"` Topic string `db:"topic"` When time . Time `db:"when"` // Tags StringSlice Tags string `db:"tags"` Duration float64 `db:"duration"` } func initDb () * gorp . DbMap { // connect to db using standard Go database/sql API // use whatever database/sql driver you wish db , err := sql . Open ( "postgres" , ` user=peterbe dbname=fastestdb password=test123 sslmode=disable` ) checkErr ( err , "sql.Open failed" ) // construct a gorp DbMap dbmap := & gorp . DbMap { Db : db , Dialect : gorp . PostgresDialect {}} // add a table, setting the table name to 'talks' and // specifying that the Id property is an auto incrementing PK dbmap . AddTableWithName ( Talk {}, "talks" ). SetKeys ( true , "Id" ) return dbmap } func checkErr ( err error , msg string ) { if err != nil { log . Fatalln ( msg , err ) } }

Top Args 🔗 To run this: go run args.go peter anders bengt And it should output: PETER ANDERS BENGT Python import sys def transform ( * args ): for arg in args : print ( arg . upper ()) if __name__ == "__main__" : transform ( * sys . argv [ 1 :]) Go package main import ( "fmt" "os" "strings" ) func transform ( args [] string ) { for _ , arg := range args { fmt . Println ( strings . ToUpper ( arg )) } } func main () { args := os . Args [ 1 :] transform ( args ) }

Top Import Alias 🔗 This example is a bit silly because you normally don't bother with an alias for short built-ins. It's import appropriate for long import nameslike: import ( pb "github.com/golang/groupcache/groupcachepb" ) You can also import packages that you won't actually use. E.g. import ( _ "image/png" // import can do magic ) Python import string as s print ( s . upper ( "world" )) Go package main import ( "fmt" s "strings" ) func main () { fmt . Println ( s . ToUpper ( "world" )) }

Top Sprintf 🔗 You might have seen things like fmt.Println("some string") and variations around it. But sometimes you might want to just generate a string using the formatting tools found under fmt without it necessarily going out on stdout . That's what fmt.Sprintf is for. Python max = 10 raise Exception ( f "The max. number is {max}" ) Go package main import "fmt" func main () { max := 10 panic ( fmt . Sprintf ( "The max. number is %d" , max )) }

Top Uniqify 🔗 The Python version is neat in that it's entirely type agnostic as long as the value supports hashing. I'm sure it's possible to do an equivalent one in Go using interface{} . Patches welcome. For faster variants in Python see Fastest way to uniqify a list in Python. For some more thoughts on this, and an example of a implementation that is not in-place check out this mailing list thread. Python def uniqify ( seq ): seen = {} unique = [] for item in seq : if item not in seen : seen [ item ] = 1 unique . append ( item ) return unique items = [ "B" , "B" , "E" , "Q" , "Q" , "Q" ] print ( uniqify ( items )) # prints ['B', 'E', 'Q'] Go package main import "fmt" func uniqify ( items [] string ) [] string { uniq := make ([] string , 0 ) seen := make ( map [ string ] bool ) // For the highest memory efficiency, do: // seen := make(map[string]struct{}) // see: https://stackoverflow.com/questions/37320287/maptstruct-and-maptbool-in-golang for _ , i := range items { if _ , exists := seen [ i ]; ! exists { uniq = append ( uniq , i ) seen [ i ] = true } } return uniq } func main () { items := [] string { "B" , "B" , "E" , "Q" , "Q" , "Q" } items = uniqify ( items ) fmt . Println ( items ) // prints [B E Q] }