Some Simple Ruby Questions - Iterators, Blocks, and Symbols

My background is in PHP and C #, but I would really like to know RoR. To this end, I began to read the official documentation. I have some questions about some code examples.

The first is with iterators:

class Array def inject(n) each { |value| n = yield(n, value) } n end def sum inject(0) { |n, value| n + value } end def product inject(1) { |n, value| n * value } end end 

I understand that yield means "execute the linked block here." What throws me is |value| n = |value| n = part of each . The rest of the blocks make more sense to me, as they seem to mimic C # style lambdas:

 public int sum(int n, int value) { return Inject((n, value) => n + value); } 

But the first example confuses me.

The other is with symbols. When will I want to use them? And why I can not do something like:

 class Example attr_reader @member # more code end 
+6
source share
5 answers

In inject or reduce method n represents the accumulated value; this means that the result of each iteration accumulates in the variable n . It can be, as in your example, a sum or a product of elements in an array.

yield returns the result of a block that is stored in n and used in the following iterations. This is what makes the result โ€œcumulative.โ€

 a = [ 1, 2, 3 ] a.sum # inject(0) { |n, v| n + v } # n == 0; n = 0 + 1 # n == 1; n = 1 + 2 # n == 3; n = 3 + 3 => 6 

Alternatively, to calculate the amount, you could also write a.reduce :+ . This works for any binary operation. If your method has the name symbol , the notation a.reduce :symbol matches the notation a.reduce { |n, v| n.symbol v } a.reduce { |n, v| n.symbol v } .

attr , and companies are actually methods. Under the hood, they dynamically determine the methods for you. It uses the character you pass to determine instance variable names and methods. :member leads to the @member instance @member and the member and member = methods.

The reason you cannot write attr_reader @member is because @member is not in itself and cannot be converted to a character; it actually tells ruby โ€‹โ€‹to get the value of the @member instance instance variable of the self object, which in the scope class is the class itself.

To illustrate:

 class Example @member = :member attr_accessor @member end e = Example.new e.member = :value e.member => :value 

Remember that access to undefined instance variables gives nil , and since the attr family of methods accepts only characters, you get: TypeError: nil is not a symbol .

As for Symbol , you can use them as strings. They make great hash keys because equal characters always refer to the same object, unlike strings.

 :a.object_id == :a.object_id => true 'a'.object_id == 'a'.object_id => false 

They are also commonly used to indicate method names, and can actually be converted to Proc s , which can be passed to methods. This allows us to write things like array.map &:to_s .

Check out this article for more interpretations of the symbol.

+3
source

To define inject you basically create a chain. In particular, the variable n in {|value| n = yield(n, value)} {|value| n = yield(n, value)} is essentially the accumulator for the block passed to inject . So, for example, to define product , inject(1) {|value| n * value} inject(1) {|value| n * value} suppose you have an array my_array = [1, 2, 3, 4] . When you call my_array.product , you start by calling inject with n = 1. each returns to the block defined in inject , which in turn displays the block passed to inject itself with n (1) and the first value in the array (1 also, in this case). This block, {|n, value| n * value} {|n, value| n * value} returns 1 == 1 * 1, which sets the variable inject n. Next, 2 is obtained from each, and the block defined in the inject block gives as yield(1, 2) , which returns 2 and assigns it n. The next 3 is obtained from each , the block gives the values โ€‹โ€‹(2, 3) and returns 6, which is stored in n for the next value, and so on. In fact, tracking the total value of the agnostic of the calculation performed in specialized routines ( sum and product ) allows you to generalize. Without this, you have to declare, for example.

 def sum n = 0 each {|val| n += val} end def product n = 1 each {|val| n *= val} end 

which annoyingly repeats.

For your second question, attr_reader and its family are themselves methods that define the appropriate access procedures, using define_method internally, in a process called metaprogramming; they are not language instructions, but simply old methods. These functions expect a character (or possibly a string) to be passed, which gives the name of the accessories you create. Theoretically, you could use instance variables such as @member , although this will be a value for which @member indicates what will be passed and used in define_method . For an example of how they are implemented, this page shows some examples of attr_ * methods.

+1
source
 def inject(accumulator) each { |value| accumulator = yield(accumulator, value) } accumulator end 

It just gives the current accumulator value and an array element for block input, and then saves the result back to the battery.

 class Example attr_reader @member end 

attr_reader is just a method whose argument is the name of the adapter you want to configure. So, in a far-fetched way, you could do

 class Example @ivar_name = 'foo' attr_reader @ivar_name end 

to create a getter method called foo

+1
source

Your confusion with the first example may be due to the fact that you are reading |value| n |value| n as one expression, but it is not.

This reformatted version may be more clear to you:

  def inject(n) each do |value| n = yield(n, value) end return n end 

value is an element in the array, and it is passed from n to any block that is passed to inject , the result of which is set to n . If this is unclear, read the each method, which takes a block and gives each element in the array. Then it should be clearer how accumulation works.

attr_reader less strange if you think this is a method for creating access methods. This is not an accessory in itself. He does not need to deal with the value of the @member variable, just his name. :member is only the interned version of the string 'member', which is the name of the variable.

You can think of characters as strings of lower weight, with the added bonus that each equal label is the same object - :foo.object_id == :foo.object_id , whereas 'foo'.object_id != 'foo'.object_id because each "foo" is a new object. You can try this for yourself at irb . Think of them as labels or primitive strings. They are surprisingly useful and come a lot, for example. for metaprogramming or as keys in hashes. As indicated elsewhere, the call to object.send :foo same as the call to object.foo

It may be worth reading some early chapters from the 'pickaxe' book to find out a little more ruby, this will help you understand and appreciate the additional rails adds.

+1
source

First you need to understand where to use the symbols and where they are not. The symbol is especially used to represent something. Example :: name ,: age like this. Here we will not perform any operations using this. The string is used only for data processing. Example: 'a = name'. Here I will use this variable 'a' for other string operations in ruby. Moreover, a character is more memory efficient than strings, and it is immutable. Therefore, the ruby โ€‹โ€‹developer prefers characters over strings.

You can even use the injection method to calculate the sum as (1..5) .to_a.inject (: +)

0
source

Source: https://habr.com/ru/post/905344/


All Articles