Menu
Coddy logo textTech

Duck Typing

Fa parte della sezione Programmazione orientata agli oggetti del percorso Ruby di Coddy. Lezione 33 di 57.

Ruby non controlla la classe di un oggetto prima di chiamare un metodo; gli basta che l'oggetto abbia il metodo. «Se cammina come un'anatra e fa qua qua come un'anatra, è un'anatra.» Questo è il duck typing: classi che non condividono alcuna superclasse possono comunque essere usate nello stesso punto:

class Duck
  def speak
    "Quack"
  end
end

class Robot
  def speak
    "Beep"
  end
end

class Radio
  def speak
    "...news..."
  end
end

[Duck.new, Robot.new, Radio.new].each { |thing| puts thing.speak }

Output:

Quack
Beep
...news...

Anche le classi integrate partecipano. Un metodo che usa solo << funziona con un array, una stringa o un tuo qualsiasi oggetto che definisce <<:

class Tally
  attr_reader :count

  def initialize
    @count = 0
  end

  def <<(_item)
    @count += 1
    self
  end
end

def export(items, target)
  items.each { |item| target << item.to_s }
  target
end

p export([1, 2], [])
p export([1, 2], +"")
puts export([1, 2, 3], Tally.new).count

Output:

["1", "2"]
"12"
3

respond_to?(:name) chiede se un oggetto ha un metodo pubblico, senza chiamarlo. Usalo quando un oggetto potrebbe supportare o meno una funzionalità facoltativa:

class Printer
  def print_page(text)
    "printing #{text}"
  end
end

class Scanner
end

[Printer.new, Scanner.new].each do |device|
  if device.respond_to?(:print_page)
    puts device.print_page("report")
  else
    puts "#{device.class} cannot print"
  end
end

Output:

printing report
Scanner cannot print

Quando l'oggetto non ha il metodo, la chiamata genera NoMethodError, il cui messaggio indica il metodo e l'oggetto. Il duck typing si basa sul fatto che ogni oggetto passato risponda ai metodi che gli vengono inviati:

def loudest(things)
  things.map(&:speak).max_by(&:size)
end

class Cat
  def speak
    "Meow"
  end
end

puts loudest([Cat.new, Cat.new])
begin
  loudest([Cat.new, 42])
rescue NoMethodError => e
  puts e.message
end

Output:

Meow
undefined method `speak' for an instance of Integer
challenge icon

Sfida

Facile

Completa le classi Printer e LineCounter e la funzione di supporto export(items, target) in functions.rb. export invia ogni elemento al target con target << item.to_s e restituisce il target. Printer#<< stampa il testo con un numero di riga, 1: text, e restituisce la stampante. LineCounter#<< conta le righe e i caratteri e restituisce il contatore; il suo to_s restituisce 3 lines, 12 chars.

Il codice fornito legge gli elementi e li esporta in un array (stampato con p), in una nuova stringa (stampata con p), in un Printer e in un LineCounter (stampato con puts).

Il tuo codice va inserito in printer.rb, line_counter.rb e functions.rb. main.rb contiene il codice di input/output fornito e non può essere modificato.

Provalo tu

require_relative 'printer'
require_relative 'line_counter'
require_relative 'functions'

# Código de entrada/salida proporcionado: mantenlo tal como está
input = []
while (line = gets)
  input << line.chomp
end
p export(input, [])
p export(input, +"")
export(input, Printer.new)
puts export(input, LineCounter.new)
quiz iconMettiti alla prova

Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.

Tutte le lezioni di Programmazione orientata agli oggetti

Esercitati da solo: Compilatore Ruby online