Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Ruby / Yukihiro Matsumoto_Programming Ruby.doc
Скачиваний:
121
Добавлен:
06.06.2015
Размер:
2.71 Mб
Скачать

Break, Redo, and Next

The loop control constructs break,redo, andnextlet you alter the normal flow through a loop or iterator.

breakterminates the immediately enclosing loop; control resumes at the statement following the block.redorepeats the loop from the start, but without reevaluating the condition or fetching the next element (in an iterator).nextskips to the end of the loop, effectively starting the next iteration.

while gets

  next if /^\s*#/   # skip comments

  break if /^END/   # stop at end

                    # substitute stuff in backticks and try again

  redo if gsub!(/`(.*?)`/) { eval($1) }

  # process line ...

end

These keywords can also be used with any of the iterator-based looping mechanisms:

i=0

loop do

  i += 1

  next if i < 3

  print i

  break if i > 4

end

produces:

345

Retry

The redostatement causes a loop to repeat the current iteration. Sometimes, though, you need to wind the loop right back to the very beginning. Theretrystatement is just the ticket.retryrestarts any kind of iterator loop.

for i in 1..100

  print "Now at #{i}. Restart? "

  retry if gets =~ /^y/i

end

Running this interactively, you might see

Now at 1. Restart? n

Now at 2. Restart? y

Now at 1. Restart? n

 . . .

retrywill reevaluate any arguments to the iterator before restarting it. The online Ruby documentation has the following example of a do-it-yourselfuntilloop.

def doUntil(cond)

  yield

  retry unless cond

end

i = 0

doUntil(i > 3) {

  print i, " "

  i += 1

}

produces:

0 1 2 3 4

Variable Scope and Loops

The while,until, andforloops are built into the language and do not introduce new scope; previously existing locals can be used in the loop, and any new locals created will be available afterward.

The blocks used by iterators (such as loopandeach) are a little different. Normally, the local variables created in these blocks are not accessible outside the block.

[ 1, 2, 3 ].each do |x|

  y = x + 1

end

[ x, y ]

produces:

prog.rb:4: undefined local variable or method `x' for #<Object:0x401c0ce0> (NameError)

However, if at the time the block executes a local variable already exists with the same name as that of a variable in the block, the existing local variable will be used in the block. Its value will therefore be available after the block finishes. As the following example shows, this applies both to normal variables in the block and to the block's parameters.

x = nil

y = nil

[ 1, 2, 3 ].each do |x|

  y = x + 1

end

[ x, y ]

»

[3, 4]

Exceptions, Catch, and Throw

So far we're been developing code in Pleasantville, a wonderful place where nothing ever, ever goes wrong. Every library call succeeds, users never enter incorrect data, and resources are plentiful and cheap. Well, that's about to change. Welcome to the real world!

In the real world, errors happen. Good programs (and programmers) anticipate them and arrange to handle them gracefully. This isn't always as easy as it might be. Often the code that detects an error does not have the context to know what to do about it. For example, attempting to open a file that doesn't exist is acceptable in some circumstances and is a fatal error at other times. What's your file-handling module to do?

The traditional approach is to use return codes. The openmethod returns some specific value to say it failed. This value is then propagated back through the layers of calling routines until someone wants to take responsibility for it.

The problem with this approach is that managing all these error codes can be a pain. If a function calls open, thenread, and finallyclose, and each can return an error indication, how can the function distinguish these error codes in the value it returns toitscaller?

To a large extent, exceptions solve this problem. Exceptions let you package up information about an error into an object. That exception object is then propagated back up the calling stack automatically until the runtime system finds code that explicitly declares that it knows how to handle that type of exception.

Соседние файлы в папке Ruby