对照 Ruby 学 Go (Part 7): Ruby与Golang方法对比

转载自: http://zonov.me/golang-for-rubyists-part-7-ruby-and-golang-methods-comparison/ 已获原作者授权

原标题: Golang for Rubyists. Part 7. Ruby and Golang, methods comparison


Hello, my dear friends. We all love Ruby (you too, right?) for its expressiveness and a set of useful methods out of the box. It would be a pleasure if when start using a new language, you had the similar methods or at least familiar ways to achieve same goals. Let’s try to pick a few useful methods from Ruby and find out, are there any equivalents in Golang for them.

Array
Let’s start with something simple:

2.2.1 :001 > array = [1,3,5,7]
 => [1, 3, 5, 7] 
2.2.1 :002 > array.shift
 => 1
2.2.1 :003 > array
 => [3, 5, 7] 
2.2.1 :004 > array.push(1)
 => [3, 5, 7, 1] 
2.2.1 :005 > array.unshift(array.pop)
 => [1, 3, 5, 7] 
So, we used four methods here: shift, unshift, push, pop. Now let me try to do something similar in Golang:

package main
 
import ("fmt")
 
func main() {
  // Initialize the slice
  array := []int{1, 3, 5, 7}
  fmt.Println(array)
   
  // Shift
  x := array[0]
  fmt.Println(x)
  array = array[1:]
  fmt.Println(array)
   
  // Push
  array = append(array, x)
  fmt.Println(array)
   
  // Pop and Unshift
  x, array = array[len(array)-1], array[:len(array)-1]
  array = append([]int{x}, array...)
  fmt.Println(array)
}
( https://play.golang.org/p/wNgO9LeX514)

Not so short and expressive, huh? But still pretty straightforward. The only confusion I can anticipate is the last example, with pop and unshift. Just to explain, at first we assign to x the last element of an array and we modify the array variable to be everything starting from the element at index 0 to the pre-last one. And at the next line we create a new slice with just x and append an array to it.
Also, you could notice here, that usage of [] to access an array/slice element is exactly the same as in Ruby (or most of the languages).

Let’s move on to the more solid examples:

2.2.1 :001 > array = [1, 3, 5, 7]
 => [1, 3, 5, 7] 
2.2.1 :002 > array.map { |a| a + 1 }
 => [2, 4, 6, 8] 
2.2.1 :003 > array
 => [1, 3, 5, 7] 
2.2.1 :005 > array.reject { |a| a % 3 == 0}
 => [1, 5, 7] 
2.2.1 :006 > array
 => [1, 3, 5, 7] 
2.2.1 :007 > array.sample
 => 7
2.2.1 :008 > array
 => [1, 3, 5, 7] 
2.2.1 :009 > 
2.2.1 :010 > array.min
 => 1
2.2.1 :011 > 
2.2.1 :012 > array.max
 => 7
2.2.1 :014 > array.shuffle
 => [5, 7, 3, 1] 
Here we iterate through a collection, without original collection modification, then we reject some value also without a modification, then we get a random element from it, then we have a basic min/max methods and a shuffle method, which shuffles an array elements. Are you optimistic about Golang abilities here? Let it a try! Nope, let me just tell you, that Go is not a functional language. Not at all. Not for an iota. The only way you can achieve map/reduce/filter functionality is by writing for loops. Also, there are no built-in min/max functions, unfortunately. Surprisingly I was able to find a shuffle implementation:

package main
 
import (
  "fmt"
  "math/rand"
)
 
func main() {
  // Initialize the slice
  array := []int{1, 3, 5, 7}
  fmt.Println(array)
  rand.Shuffle(len(array), func(i, j int) {
    array[i], array[j] = array[j], array[i]
  })
  fmt.Println(array)
}
Btw it still uses two for loops under the hood: https://golang.org/src/math/rand/rand.go#L232. Interesting to notice here is that it’s possible to pass a function to a method in Golang.

Just to give an impression, here is the possible implementation of our own Filter function in Golang:

package main
 
import ("fmt")
 
func main() {
  array := []int{1, 3, 5, 7}
  filteredArray := Filter(array, func(i int) bool {
    return i%3 != 0
  })
  fmt.Println(filteredArray)
}
 
func Filter(in []int, fn func(int) bool) []int {
  out := make([]int, 0, len(in))
 
  for i := 0; i < len(in); i++ {
    current := in[i]
 
    if fn(current) {
      out = append(out, current)
    }
  }
 
  return out
}
( https://play.golang.org/p/LFvueXzO-BU. Here is a version, using interfaces, more generic, but still far from ideal https://play.golang.org/p/N9JvUXo7ugq)

As you can see, this will work only with slices of integers. In the link above you can find a more generic implementation. It uses reflection mechanism of Golang, which we didn’t explore yet.
So, this function may look cumbersome, but let’s take a look onto Ruby’s map method under the hood:

static VALUE
rb_ary_collect(VALUE ary)
{
    long i;
    VALUE collect;
 
    RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length);
    collect = rb_ary_new2(RARRAY_LEN(ary));
    for (i = 0; i < RARRAY_LEN(ary); i++) {
        rb_ary_push(collect, rb_yield(RARRAY_AREF(ary, i)));
    }
    return collect;
}
Looks pretty similar, isn’t it? Sure, in Ruby we don’t work with types – that’s the only difference. So, long story short, use for loops, that’s the way to go.
But also one thing I want to mention is that there is a more convenient way to iterate through a collection, here how it looks like (works for both maps and arrays):

package main
 
import ("fmt")
 
func main() {
  array := []int{1, 3, 5, 7}
  for i := range array {
    fmt.Println(i * 2)
  }
}
( https://play.golang.org/p/6g28EUCvQ6f)


Hashes
One of the most heavily used data structures in Ruby is Hash.
Just kiddin, I have no idea, which is the most heavily used one. Let’s take a look at these examples, where we apply a couple of useful functions to it:

2.2.1 :001 > hash = { foo: 'bar', fizz: 'buzz', berlin: 'rain', munich: 'beer' }
 => {:foo=>"bar", :fizz=>"buzz", :berlin=>"rain", :munich=>"beer"} 
2.2.1 :003 >   
2.2.1 :004 >   hash.values
 => ["bar", "buzz", "rain", "beer"] 
2.2.1 :005 > hash.keys
 => [:foo, :fizz, :berlin, :munich] 
2.2.1 :006 > 
2.2.1 :008 > hash.values_at(:munich, :berlin)
 , > ["beer", "rain"] 
Nothing magical, just retrieving all values, all keys, and values by multiple keys, should be easy-peasy?

package main
 
import ("fmt")
 
func main() {
  hash := map[string]string{"foo": "bar", "fizz": "buzz", "berlin": "rain", "munich": "beer"}
  fmt.Println(hash)
 
  values := make([]string, 0, len(hash))
  for _, value := range hash {
    values = append(values, value)
  }
  fmt.Println(values)
 
  keys := make([]string, 0, len(hash))
  for key := range hash {
    keys = append(keys, key)
  }
  fmt.Println(keys)
   
  valuesAt := []string{hash["munich"], hash["berlin"]}
  fmt.Println(valuesAt)
}
( https://play.golang.org/p/YN0xnhly-r9)

I am honestly not sure about the last one, probably there is a way to make it more readable. But anyway, beauty of Go in it’s straightforwardness

猜你喜欢

转载自blog.csdn.net/yuanlaidewo000/article/details/80896873
今日推荐