Giter VIP home page Giter VIP logo

go-for-perl-hackers's Introduction

go-for-perl-hackers

The primary aim of this cheat sheet is to help Perl programmers get up and running with Go.

Your editor

vim

Consider adding the vim-go plugin to your .vimrc

If you're using vim-plug, that would look something like:

Plug 'fatih/vim-go'

If you're using Pathogen, that would look something like:

runtime bundle/vim-pathogen/autoload/pathogen.vim
" Bundle: tpope/vim-pathogen
call pathogen#infect()

" Bundle: https://github.com/fatih/vim-go.git

Now, open vim after installing vim-go and enter :GoInstallBinaries

Also, you can add goimports:

First install it: go get golang.org/x/tools/cmd/goimports

Then add the following to your .vimrc

let g:go_fmt_command = "goimports"

If your editor is set up to display tabs visually, you may want to disable that for Go files.

autocmd FileType go setlocal nolist

shortcuts

daf in vim will now allow you to cut an entire function without first needing to select it.

vim-go commands

:GoBuild

go build

:GoRun

go run

:GoGenerate

go generate

:GoRename

Call this when your cursor is over something you'd like to rename, and it will be renamed in all of the appropriate locations.

:GoTest

Run this in order to test your code without leaving your vim session.

:GoTestFunc

Run this when inside a test function and only this test function will be run. Equivalent of go test -run MyFunctionName.

:GoAlternate

Toggles file between foo.go and foo_test.go

:GoDef

Takes you to the location where an item is defined. Keep running this to move further up the stack.

:GoDefPop

Pops the stack which you created with :GoDef, taking you back to the previous location(s) you called :GoDef from.

:GoDecls

See functions which are declared in the current file.

:GoDeclsDir

Like :GoDecls but finds all the functions declared in the directory of the file you're editing.

:GoReferrers

Find other places where a function or variable is being invoked.

:GoDoc

Look up docs for a function.

:GoInfo

Get a function's input and output parameters.

:GoDescribe

Like :GoInfo, but with more info.

:GoFiles

List all files in package.

:GoDeps

List dependencies.

:GoWhicherrs

Get info on what sorts of errors an err variable may contain.

:GoCallers

Find out where a function callers are.

:GoImpl

Generate stub methods required by an interface.

:GoFreevars

Go vs Perl

In this section we'll document some commonly used Perl constructs and try to find their equivalents in Go.

Comments

Perl:

# single line

=pod

Multi line

=cut

Go:

// single line (C++-style)

/*
Multi-line (C-Style)
*/

Print

Printing strings

Perl:
print 'hello, world';
Go:
package main

import "fmt"

func main () {
    fmt.Println("hello, world")
}

Formatted print statements.

Perl:
printf('We are open %i days per %s', 7, 'week');
Go:
package main

import ( "fmt" )

func main() {
    fmt.Printf("We are open %d days per %s", 7, "week")
}

See golang.org/pkg/fmt/

Printing from within a test

Perl:
diag 'foo happens';
Go:
t.Log("foo happens")
t.Logf("We are open %d days per %s", 7, "week")

Variables

Environment Variables

Perl:
$ENV{FOO} = 'bar';
local $ENV{FOO} = 'bar'; # Same as above, but with local scope

print "GOPATH: $ENV{GOPATH}\n";
Go:
os.Setenv("FOO", "bar")

fmt.Println("GOPATH: ", os.Getenv("GOPATH"))

Variable Assignment

Perl:
my $foo = 'bar';
my $pi = 3.14;
my $no_assignment;
Go:
// the following assignments are equivalent
var foo = "bar"
foo := "bar"

var pi float32 = 3.14  // explicit cast as float32
pi := float32(3.14)    // explicit cast as float32
pi := 3.14             // implicit cast as float64
pi := "3.14"           // implicit cast as string

var noAssignment string // equivalent to: noAssignment := ""

See golang.org/ref/spec#Rune_literals

Multiple Variables

Declare without explicit values
Perl:
my ($foo, $bar);
Go:
var foo, bar int
var nothing []string // create an empty slice
Declare with explicit values
Perl:
my ($i, $j) = (1, 2);
Go:
var i, j int = 1, 2

Double vs Single Quotes

Perl:
my $foo = 'bar'; // no variable interpolation
my $bar = "$foo baz"; // allow for variable interpolation
Go:
foo := "ๆœฌ" // implicitly cast as a string
foo := 'ๆœฌ' // implicitly cast as a rune

Multiline strings

Perl:
my $long_string = <<'EOF';
my multiline
string
EOF

Use double quotes <<"EOF"; if you need to interpolate variables.

Go:
longString := `
my multiline
string
`

Boolean checks (true/false)

Perl:
my $success = 1;    # true
$success = 'foo';   # true
$success = 0;       # false
$success;           # (undef) false

if ($success) {
    print "This succeeded";
}

if ( !$success ) {
    print "This failed";
}
Go:
var success bool

success = true
success = false

if success == true {
    fmt.Println("This succeeded")
}

if success {
    fmt.Println("This succeeded")
}

if success == false {
    fmt.Println("This failed")
}

if !success {
    fmt.Println("This failed")
}

Checking for (un)definedness

Perl:
my $foo;
if ( ! defined $foo ) {
    ...;
}
Go:
var myString string

if myString == "" {
    fmt.Println("Empty")
}


var mySlice []int

if mySlice == nil {
    fmt.Println("nil")
}

Incrementing and Decrementing Integer

Perl:

See https://perldoc.perl.org/perlop.html#Auto-increment-and-Auto-decrement

$i = 0;  $j = 0;
print $i++;  # prints 0
print ++$j;  # prints 1

$i = 0;  $j = 0;
print $i--;  # prints 0
print --$j;  # prints -1
Go:
counter := 1
counter++
counter--

String Concatenation

Perl:
my $foo = 'go';
my $bar = 'pher';

$gopher = "$foo$bar";
$gopher = $foo . $bar;
$gopher = join q{}, $foo, $bar;
$gopher = sprintf '%s%s', $foo, $bar;
Go:
package main

import (
    "fmt"
    "strings"
)

func main() {
    var gopher string

    gopher = foo + bar
    gopher = fmt.Sprintf("%s%s", foo, bar)
}
package main

import (
    "fmt"
    "strings"
)

func main() {
    foo := "go"
    bar := "pher"

    gopher = strings.Join([]string{"go", "pher"}, "")
    fmt.Println(gopher)
}
package main

import (
    "bytes"
    "fmt"
)

func main() {
    var buffer bytes.Buffer
    foo := "go"
    bar := "pher"

    buffer.WriteString(foo)
    buffer.WriteString(bar)
    fmt.Println(buffer.String())
}

Constants

Perl:
use Const::Fast;
const my $hello => 'Hello, world';
Go:
// Create an *untyped* string constant
const hello = "Hello, world"

// Create a typed string constant
const hello string = "Hello, World"

Create multiple constants with one const declaration:

const(
    hello   = "Hello, world"
    goodbye = "Goodbye!"
)

Constants cannot be declared using the := syntax.

Lists

Create an Array

Perl:
my @foo = (1..3);
my $first = $foo[0];
Go:
foo := [3]int{1,2,3}
first := foo[0]

Note that creating an empty array in Go means that it will be populated by the type's default values:

var bar [5]int \\ creates an array of [0,0,0,0,0]

Size of an array:

Perl:
my $size = @array;
Go:
size := len(array)

Hashes / Structs

Perl:
use Data::Printer; # exports p()

my %foo = (
    X => 1,
    Y => 2,
);

$foo{X} = 4;
print $foo{X}; # prints 4

p %foo;
# prints:
# {
#    X => 4,
#    Y => 2,
# }

delete $foo{X};
Go:
package main

import "fmt"

type Vertex struct {
    X int
    Y int
}

func main() {
    v := Vertex{1, 2}
    v.X = 4
    fmt.Println(v.X) // prints 4
    fmt.Printf("%+v\n", v) // prints {X:4 Y:2}

    // additional examples
    v1 = Vertex{1, 2}  // has type Vertex
    v2 = Vertex{X: 1}  // Y:0 is implicit
    v3 = Vertex{}      // X:0 and Y:0

    delete(v, "X")
}

Iterating Over a List

Perl:
my @foo = ('foo', 'bar', 'baz');

for my $value ( @foo ) {
    print "$value\n";
}
my @foo = ('foo', 'bar', 'baz');

for (@foo) {
    print "$_\n";
}
// Print array index for each element
my @foo = ('foo', 'bar', 'baz');

for my $i (0..$#foo) {
    print "$i: $foo[$i]\n";
}
Go:
package main

import (
	"fmt"
)

func main() {
	foo := [3]int{1, 2, 3}

	for i, v := range foo {
		fmt.Printf("index: %v value: %v\n", i, v)
	}
}

Splitting a string

my @list = split ',', 'a,b,c'
package main

import (
	"strings"
)

mySlice := strings.Split("a,b,c", ",")

Iterating Over a Hash/Map

Perl:
my %hash = ( key_1 => 'foo', key_2 => 'bar', );
for my $key ( keys %hash ) {
    printf( "key: %s value: %s\n", $key, $hash{$key} );
}
Go:
package main

import (
	"fmt"
)

func main() {
	myMap := map[string]string{"key1": "foo", "key2": "bar"}

	for k := range myMap {
		fmt.Printf("key: %s value: %s\n", k, myMap[k])
	}
}

Checking if a Hash/Map Key Exists

Perl:
my %pages = ( home => 'https://metacpan.org' );
if ( exists $foo{home} ) {
    ...
}
Go:

https://stackoverflow.com/a/2050629/406224

package main

import "fmt"

func main() {
	pages := make(map[string]string)
	pages["home"] = "https://metacpan.org"
	if _, ok := pages["home"]; ok {
	    fmt.Println("ok")
	}
}

Deleting a Hash/Map Key

Perl:
my %pages = ( home => 'https://metacpan.org' );
delete $pages{home};
Go:
package main

import "fmt"

func main() {
	pages := make(map[string]string)
	pages["home"] = "https://metacpan.org"
  delete(pages, "home")
}

Getting an array Hash/Map Keys

Perl:
my %pages = ( home => 'https://metacpan.org' );
my @keys = keys %pages;
Go:
package main

func main() {
	pages := make(map[string]string)
	pages["home"] = "https://metacpan.org"

	keys := []string{}
	keys = append(keys, "foo")
}

Slices:

Perl:
my @array = (0..5);
my @slice = @list[2..4];
Go:
array := [6]int{0,1,2,3,4,5}
var slice []int = array[2:4]

var myslice []int    // create an empty slice of integers
var nothing []string // create an empty slice of strings

Note that arrays in Go have a fixed size, whereas slices are dynamically sized.

Also:

A slice does not store any data, it just describes a section of an underlying array.

Changing the elements of a slice modifies the corresponding elements of its underlying array.

Other slices that share the same underlying array will see those changes.

See https://tour.golang.org/moretypes/8

Note also that slices in Go can use defaults for lower and upper bounds. That means that for the array of 10 integers var a [10]int, the following slices are equivalent:

a[0:10]  // explicit lower to upper bound
a[:10]   // use default lower bound (0)
a[0:]    // use default upper bound (0)
a[:]     // use default upper and lower bounds (0 and 10)

Note that the lower bound is the starting point in the index (ie 0) and the length of the slice is the upper bound, which is why the entire slice consists of a[0:10 and not a[0:9].

See https://tour.golang.org/moretypes/10

Appending Slices:

Perl:
my @array = (0..5);
my @slice = @list[2..4];
push @slice, 11, 12;

Note that in Perl, a slice of an array is also an array, so there's no need to make a distinction between the two.

Go:
array := [6]int{0,1,2,3,4,5}
var slice []int = array[2:4]
slice = append(slice, 11, 12)

Dumping Data Structures

To your terminal

Perl:
use strict;
use warnings;
use feature qw( say );

use Data::Printer; # exports p() and np()

my %foo = ( a => 'b' );
p( %foo );

# or

say np( %foo );
Go:
package main

import "fmt"

func main() {
    var config struct {
        user    string
        pass    string
    }

    config.user = "florence"
    config.pass = "machine"

    fmt.Printf("%+v", config)

    return
}

Or:

package main

import "github.com/davecgh/go-spew/spew"

func main() {
    var config struct {
        user    string
        pass    string
    }

    config.user = "florence"
    config.pass = "machine"

    spew.Dump(config)

    return
}

To disk (write)

Perl:
use Data::Printer; # exports np()
use Path::Tiny qw(path);

my @list = ( 1..3 );
path('/tmp/foo.txt')->spew( np( @list ) );
Go:
package main

import (
    "log"
    "os"

    "github.com/davecgh/go-spew/spew"
)

func main() {
    list := [3]int{1, 2, 3}

    file, err := os.OpenFile(
        "/tmp/foo.txt",
        os.O_CREATE|os.O_WRONLY,
        0666,
    )

    if err != nil {
        log.Fatal(err)
    }

    spew.Fdump(file, list)
    file.Close()
}

To disk (append)

Perl:
use Data::Printer; # exports np()
use Path::Tiny qw(path);

my @list = ( 1..3 );
path('/tmp/foo.txt')->append( np( @list ) );
Go:
package main

import (
    "log"
    "os"

    "github.com/davecgh/go-spew/spew"
)

func main() {
    list := [3]int{1, 2, 3}

    file, err := os.OpenFile(
        "/tmp/foo.txt",
        os.O_APPEND|os.O_CREATE|os.O_WRONLY,
        0666,
    )

    if err != nil {
        log.Fatal(err)
    }

    spew.Fdump(file, list)
    file.Close()
}

File Operations

Creating a directory

Perl:
use Path::Tiny qw( path );
use Try::Tiny qw( catch try );

my $dir = '.my-perl-cache';
try {
    path($dir)->mkpath( { chmod => 0644 });
}
catch {
    die sprintf "Could not create dir %s because of %s", $dir, $_;
};
Go:
package main

import (
	"log"
	"os"
)

func main() {
	cacheDir := ".my-go-cache"
	if err := os.MkdirAll(cacheDir, 0644); err != nil {
		log.Printf("Cannot create dir %s because %v", cacheDir, err)
	}
}

Read an Entire File

Perl:
use Path::Tiny qw( path );

my $content = path('path', 'to', 'file')->slurp_utf8;
Go:

Note that in this case content is []byte

    content, err := ioutil.ReadFile(
        filepath.Join("path", "to", "file")
    )
    if err != nil {
        log.Fatal(err)
    }

    // convert byte array to string
    contentAsString := string(content[:])

Read First Line of a File

Perl:

In the Perl example, we'll chomp the line to make explicit that newlines need to be handled.

use Path::Tiny qw( path );

my $first_line;
my $fh = path('/path/to/file')->openr_utf8;

while (my $line = <$fh>) {
    $first_line = $line;
    chomp $first_line;
    last;
}

print $first_line, "\n";
Go:

scanner.Scan() helpfully trims newlines for us.

import(
    "fmt"
    "log"
)

func main() {
    file, err := os.Open("/path/to/file")
    if err != nil {
        log.Fatal(err)
    }
    defer file.Close()

    scanner := bufio.NewScanner(file)

    var firstLine string
    for scanner.Scan() {
        firstLine = scanner.Text()
        break
    }
    if err := scanner.Err(); err != nil {
        log.Fatal(err)
    }

    fmt.Println(firstLine)
}

Flow Control

if

Perl:
if ( $foo > 1 ) {
    print 'bar';
}
Go:
if ( foo > 1 ) {
    fmt.Println("bar")
}

// parens are optional
if foo > 1 {
    fmt.Println("bar")
}

else

Perl:
if ( $foo > 1 ) {
    print 'bar';
}
else {
    print 'baz';
}
Go:
if foo > 1 {
     fmt.Println("bar")
} else {
     fmt.Println("baz")
}

elsif / else if

Perl:
if ( $foo > 1 ) {
    print 'bar';
}
elsif ( $foo < 10 ) {
    print 'baz';
}
Go:
if foo > 1 {
     fmt.Println("bar")
} else if foo < 10 {
     fmt.Println("baz")
}

Loops

For loops

Perl:
my $sum;
for ( my $i = 0 ; $i < 10 ; $i++ ) {
    $sum += $i;
}
Go:
sum := 0
for i := 0; i < 10; i++ {
    sum += i
}

While loops

Perl:
my $sum = 0;
my $i = 0;
while ( $i < 10 ) {
    $sum += $i++;
}
Go:
// The init and post statement in a Go for loop are optional.
sum := 0
i := 0
for i < 10 {
    sum += i
    i += 1
}

Infinite loops

Perl:
while (1) {
}
Go:
for {
}

Short-circuiting a loop iteration

Perl:

while (1) {
    ...
    next if $foo eq 'bar';
    ...
}

Go:

for {
    if foo == "bar" {
        continue
    }
    // Won't get here if continue is called
}

Note that continue will immediately begin the next iteration of the innermost for loop.

Terminating a loop

Perl:

while (1) {
    ...
    last if $foo eq 'bar';
    ...
}

Go:

for {
    if foo == "bar" {
        break
    }
    // Won't get here if break is called
}

Note that break will exit the enclosing loop at the point where it is called.

Functions

Functions without signatures

Perl:
sub foo {
    print 'ok';
}
foo();
Go:
package main

import "fmt"

func main() {
	foo()
}
func foo() {
	fmt.Println("foo")
}

Running Tests

Perl:

$ perl Makefile.PL
$ make
$ make test

or

$ prove -l t/path/to/test.t

Use the -v flag for verbose output:

$ prove -lv t/path/to/test.t

Go:

$ go test

Use the -v flag for verbose output:

$ go test -v

If you're using vim-go, use :GoTest either from your foo.go or foo_test.go. (Note, you can also use :GoAlternate to toggle between the two files.)

To test a subset of functions:

$ go test -run regexp

If you're using vim-go, move your cursor to the name of the function you'd like to test. Running :GoTest here will run the function you're currently in.

To bypass Go's test caching:

$ go test -count=1

Debugging

Printing Stack Traces

Perl:
use Carp qw( longmess );
print longmess();
Go:
package main

import (
	"runtime/debug"
)

func main() {
	debug.PrintStack()
}

Sleep

Perl:

sleep 60;

Go:

package main

import (
    "time"
)

func main() {
    time.Sleep(60 * time.Second)
}

Parsing URIs

Perl:

use Mojo::URL ();
my $url = Mojo::URL->new('https://www.google.com/search?q=schitt%27s+creek');
print $url->query->param('q'); # schitt's creek

Go:

import (
    "fmt"
    "log"
    "net/url"
)

func main() {
    url, err := url.Parse("https://www.google.com/search?q=schitt%27s+creek")
    if err != nil {
        log.Fatal(err)
    }
    q := url.Query()
    fmt.Println(q.Get("q")) // schitt's creek
}

Changing URI Query Params

Go:

package main

import (
	"fmt"
	"net/url"
)

func main() {
	url, _ := url.Parse("https://example.com")

	// Begin searches at today's date
	q := url.Query()
	q.Set("activity", "dance")
	q.Set("type", "flash")
	url.RawQuery = q.Encode()

	fmt.Println(url)
}

Command Line Scripts

Print first argument to a script

print $ARGV[0], "\n" if $ARGV[0];
package main

import (
        "fmt"
        "os"
)

func main() {
        if len(os.Args) > 1 {
                fmt.Printf("%v\n", os.Args[1])
        }
}

Exiting a script

Perl:
exit(0);
Go:
import("os")

os.Exit(0)

go-for-perl-hackers's People

Contributors

jonjensen avatar oalders avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.