(WIP) Ruby to Go: How Can I Do X in Ruby With Go? (Part I)

I am a programmer who can write decent Ruby and some Javascript.

These two languages were all I know. I wanted to add Go to my list of programming language, so I started learning Go.

It’s boring to read programming books to study programming languages, so I decided to learn Go by porting some programs written in Ruby.

While I was porting Ruby program to Go, I came to think it is useful if there is a cheatsheet that I can loop up in order to convert idiomatic Ruby code to Go.

Ruby and Go are totally different language, so sometimes it is impossible to simply translate Ruby code to Go. However, it is possible in most cases to write Go code that is sematically equivalant to Ruby code.

So, here is a How can I do X in Ruby with Go? cheetsheet.

I hope you find it useful.

Contents of this artcile

Array and Enumerable Operation

Method Definition

MathematicOperation

Misc

Array and Enumerable Operation

Array is very powerful data structure and enumerable is probably the most frequently used object in Ruby.

In Go, we have two different enumerable data structures: array and slice. I don’t write about details about them since it is not the goal of this post, but array is low-level data structure that slice refers to.

Create array

Ruby:

1
2
numbers = [1,2,3]
fruits = ["apple", "banana", "grape"]

Go:

1
2
numbers := []int{1,2,3}
fruits := []string{"apple", "banana", "grape"}

In the case of Go, numbers and words are slice, not array. Array is primitive data structure, not frequently used in Go code. If you want to archive similar things to Ruby array, slice should work for you.

Append an element to array

Ruby:

1
2
numbers = [1,2,3]
numbers << 4

Go:

1
2
numbers := []int{1,2,3}
numbers.append(numbers, 4)

append adds elements to slice and return new slice. Therefore, you have to reassign to itself.

Concatenate arrays

Ruby:

1
2
3
numbers1 = [1,2,3]
numbers2 = [4,5,6]
numbers1 = numbers1 + numbers2

Go:

1
2
3
numbers1 := []int{1,2,3}
numbers2 := []int{4,5,6}
numbers1 = append(numbers1, numbers2...)

... suffix on the slice indicates that it should be passed as the variadic argument, expanded as each int elements inside append. Thus, this is equivalent to below:

1
2
numbers1 := []int{1,2,3}
numbers1 = append(numbers1, 4, 5, 6)

Create multi dimension array

Ruby:

1
multi_array = [[1,2,3],[4,5,6]]

Go:

1
var mul [][]int = [][]int{ {1, 2, 3}, {4,5,6} }

Create empty array

Ruby:

1
array = []

Go:

1
var array []int

When slice is declared, but not initialised, the slice points to an array of size 0.

Iterate on array

Ruby:

1
2
numbers = [1,2,3]
numbets.each {|num| puts num }

Go:

1
2
3
4
numbers := []int{1,2,3}
for _, num := range numbers {
  fmt.Println(num)
}

If you want to access the index while iterating over the slice, replace _ with other variable, for example, i.

1
2
3
4
numbers := []int{1,2,3}
for i, num := range numbers {
  fmt.Println("index: ", i, "number: ", num)
}

Looping N times

Ruby:

1
5.times {|num| puts num}

Go:

1
2
3
for num:=0; num <5; num++ {
  fmt.Println(num)
}

Clone array

Ruby:

1
new_array = old_array.clone

Go:

1
2
new_array := make([]int, len(old_array))
copy(new_array, old_array)

Accessing elements of array by range

Ruby:

1
2
numbers=[1,2,3,4,5]
numbers[0..3]

Go:

1
2
ary := []int{1,2,3,4,5}
ary[0:4]

Note that, with from:to, to is the index where to end but not including the index itself.

Compare array

Ruby:

1
2
3
if ary1 == ary2
  puts "Same array"
end

Go:

1
2
3
4
5
6
7
8
same := true
for i, elm:= range ary1 {
   if ary2[i] != r { same = false }
}

if same == true {
  fmt.Println("Same slice")
}

You cannot compare slice in Go. You will get slice can only be compared to nil error if you try to do that.

Check if array includes an element

Ruby:

1
2
3
4
5
fruits = ["apple", "banana", "grape"]

if fruits.include?("apple")
  puts "include!"
end

Go:

1
2
3
4
5
6
7
8
9
10
11
12
include := false
fruits := []string{"apple", "banana", "grape"}
for _, elm := range fruits {
  if elm == "apple" {
    include = true
    break
  }
}

if include == true {
  fmt.Println("include!")
}

Method Definition

There are two things that are equivalant to Ruby’s method in Go: method and function. Method is a type of function but requires specific receiver.

Define a method with optional parameter

Ruby:

1
2
3
def greeting(word="hello!")
  puts word
end

Go:

This is not possbile in Go. Go does not support optional parameter in function or method definition. One workaround is using struct.

1
2
3
4
5
6
7
8
9
10
11
12
type greetingArg struct { word string }
func greeting(opt greetingArg) {
  word := opt.word
  if word == "" {
    fmt.Println("hello!")
  } else {
    fmt.Println(word)
  }
}

greeting(greetingArg{})
greeting(greetingArg{"bye!"})

Define a method with variable length argument

Ruby:

1
2
3
def foo(*args)
  args.each {|arg| puts arg}
end

Go:

1
2
3
4
5
func foo(arg ...int) {
  for _, arg := range arg {
    fmt.Prinln(arg)
  }
}

Mathematic Operation

Modular of negative number

Both Ruby and Go supports modular of negative number. However, their behavior is different.

Ruby:

1
-5 % 3 => 1

Go:

1
-5 % 3 => -2

Go follows truncated toward zero for the division of negative number.

If you want to get the same value that Ruby returns, here is how to do this.

Go:

1
2
3
4
5
divider := 3
mod := -5 % divider
if mod < 0 {
  mod = mod + divider
}

Note that values returnd by Ruby and Go are both mathematically correct. It’s just there are two ways to define negative modulo.

Misc

Nil checking

Ruby:

1
2
3
if val.nil?
  puts "val is nil"
end

Go:

1
2
3
4
5
6
7
8
9
var str string
if str =="" {
  fmt.Println("str is empty")
}

var i int
if i == 0 {
  fmt.Println("i is zero")
}

When you declear a variable without intialization, the variable is set to zero value for its type. Below is default zero value for primitive types.

Type Value
string ‘’
int 0
float 0.0
boolean false
pointer nil
interface nil
slice nil
map nil

Checking the class

Ruby:

1
puts "abc".class

Go:

1
2
3
import "reflect"

fmt.Println(reflect.TypeOf("abc"))

Comments

« シャミアの秘密分散法で秘密のデータを分割管理する Experiment To Suspend/Resume Docker Container With CRIU »