zellux 的博客

《Ruby Programming Language》笔记


Chapter 3 Datatypes and Objects

"360 degrees=#{2*Math::PI} radians" # "360 degrees=6.28318530717959 radians"
$salutation = 'hello' # Define a global variable
"#$salutation world" # Use it in a double-quoted string
"My phone #: 555-1234" # No escape needed
"Use \#{ to interpolate expressions" # Escape #{ with backslash

Ruby will create a new object for each iteration. For efficiency, you should avoid using literals within loops.

The << operator appends its second operand to its first. This operator is very different from +; it alters the lefthand operand rather than creating and returning a new object.

To alter individual characters of a string, simply use brackets on the lefthand ide of an assignment expression.

In general, Symbol objects work more efficiently as hash keys than strings do.

Two-dot range: the range is inclusive and the end value is part of the range

Three-dot range: the range is exclusive and the end value is not part of the range

You can convert a String to a Symbol using the intern or to_sym methods.

Ruby’s convention of == and equal() is just about the opposite of Java’s.

Any object may be frozen by calling its freeze method. A frozen object becomes immutable.

Chapter 5 Statements and Control Structures

The if modifier has very low precedence and binds more loosely than the assignment operator.

The following two lines of code are different:

y = x.invert if x.respond_to? :invert
y = (x.invert if x.respond_to? :invert)

The inject method behaves like foldr in Haskell and reduce in Python.

A fundamental issue is deciding which party controls the iteration, the iterator or the client that uses the iterator. When the client controls the iteration, the iterator is called an external iterator, and when the iterator controls it, the iterator is an internal iterator.

If you want to return more than one value in a block, you can use next instead of return.

Most Ruby programmers omit return when it is not necessary. Instead of writing return x as the last line of a method, they would simply write x.

When next is used within a block, it causes the block to exit immediately, returning control to the iterator method, which may then begin a new iteration by invoking the block again.

Compute factorial of x, or use 0 if the method raises an exception: y = factorial(x) rescue 0

Fibers can be thought of as independent paths of execution within a single thread of execution. Unlike threads, however, there is no scheduler to transfer control among fibers; fibers must explicitly schedule themselves with transfer.

Chapter 6 Methods, Procs, Lambdas, and Closures

An important feature of procs and lambdas is that they are closures: they retain access to the local variables that were in scope when they were defined, even when the proc or lambda is invoked from a different scope.

Block arguments prefixed with ampersands must really be the last one. Because blocks are passed unusually in method invocations, named block arguments are different and do not interfere with array or hash parameters in which the brackets and braces have been omitted.

When & is used before a Proc object in a method invocation, it treats the Proc as if it was an ordinary block following the invocation.

a, b = [1,2,3], [4,5] # Start with some data.
summation = {|total,x| total+x } # A Proc object for summations.
sum = a.inject(0, &summation) # => 6
sum = b.inject(sum, &summation) # => 15

In Ruby 1.9, the Symbol class defines a to_proc method, allowing symbols to be prefixed with & and passed to iterators. When a symbol is passed like this, it is assumed to be the name of a method.

words = ['and', 'but', 'car'] # An array of words
uppercase = &:upcase # Convert to uppercase with String.upcase
upper = {|w| w.upcase } # This is the equivalent code with a block

Ruby 1.9 syntax allows lambdas to be declared with argument defaults, just as methods can be:

zoom = ->(x,y,factor=2) { [x*factor, y*factor] }

The Proc class also defines the array access operator to work the same way as call.

f = {|x,y| 1.0/(1.0/x + 1.0/y) }
z = f[x,y]

Ruby 1.9 offers an additional way to invoke a Proc object; as an alternative to square brackets, you can use parentheses prefixed with a period:

z = f.(x,y)

Chapter 7 Classes and Modules

When the initialize method is invoked, self holds an instance of the Point class. But the code outside of that method is executed as part of the definition of the Point class.

If we want the expression 2*p to return the same result as p*2, we can define a coerce method.

A protected method defined by a class C may be invoked on an object o by a method in an object p if and only if the classes of o and p are both subclasses of, or equal to, the class C.

To invoke the private utility method defined in the previous code, you can use the send method, or you can use instance_eval to evaluate a block in the context of the object.

Class methods can also be defined using self instead of the class name.

Class variables have names that begin with @@.

Remember that public, private, and protected apply only to methods in Ruby. Instance and class variables are encapsulated and effectively private, and constants are effectively public.

The upshot is that, in Ruby, you should only subclass when you are familiar with the implementation of the superclass. If you only want to depend on the public API of a class and not on its implementation, then you should extend the functionality of the class by encapsulating and delegating to it, not by inheriting from it.

Class#new, is an instance method, and the other, Class::new, is a class method.

Class is a subclass of Module. This means that all classes are modules, but not all modules are classes. Classes can be used as namespaces, just as modules can. Classes cannot, however, be used as mixins.