2012-05-30 3 views
2

Например, если у меня естьКак разрешить только аргумент функции Ruby для определенного типа?

def function(arg) 
    #do stuff 
end 

как я только позволяют arg быть массив? Я могу сделать

def function(arg) 
    if arg.class != 'Array' 
    return 'Error' 
    else 
    #do stuff 
    end 
end 

но есть ли лучший способ сделать это?

+1

вместо 'возвращения«Error'' вы, вероятно, хотите сделать 'поднять ArgumentError', но кроме этого я не думаю, что его собирается получить намного лучше –

ответ

8

Вы не можете сделать def function(Array arg) как и в других языках, но вы можете заменить четыре строки вашего второго фрагмента с помощью одного одного :

def function(arg) 
    raise TypeError unless arg.is_a? Array 
    # code... 
end 
2

Считается, что Ruby динамически типизирован, вы не можете навязывать это так же, как на C. Вместо сравнения со строкой вы можете фактически сравнить ее с классом.

arg.is_a?(Array)

Чтобы улучшить пример, который я бы написал:

def function(arg) 
    raise TypeError unless arg.is_a?(Array) 
    # Do stuff 
end 
1

Ruby не поддерживает проверку типа - по крайней мере, не в том смысле, что он может объявлять типы аргументов как часть подпись метода. Как правило, вызывающий отвечает за передачу правильных объектов, или переданные объекты несут ответственность за преобразование самих себя. Тем не менее, вы, безусловно, можете делать свои собственные принуждения. Фактически, about.com имеет an example, используя оператор case для выполнения такого типа проверки типов.

Вот некоторые дополнительные примеры:

# Ask your object to convert itself to an array. 
def foo my_object 
    my_object.to_a 
end 

# Give your object a #to_a method if it doesn't already have one. 
def foo my_object 
    unless my_object.respond_to? :to_a 
    def my_object.to_a 
     # perform your type conversion 
    end 
    end 
end 

# Do your own type conversions. 
def foo my_object 
    case my_object 
    when Array 
    p my_object 
    when String 
    my_object.scan /\d+/ 
    end 
end 

Вы можете смешивать и сочетать любого из этих методов, и есть, конечно, другие. Ruby - очень гибкий язык.

+1

Вы можете typecheck свое сердце в Ruby, но это идет против потока языка. – steenslag

3

Другие указали, как вы можете технически применять тип аргумента, но вы сражаетесь с фундаментальной битвой с рубиновым мышлением. Google для «утиной печати».

В мире рубинов мы обычно не беспокоимся о типе аргумента, а скорее о том, соответствует ли он интерфейсу того, что мы хотим с ним делать. Другими словами, делает ли это кражу, как утка? Достаточно хорошо!

Давайте предположим, что вы пытаетесь использовать массив для чего-то:

def function(arg) 
    arg.each do |a| 
    puts a 
    end 
end 

Если вы называете это как: function(1), вы получите NoMethodError: undefined method 'each'

Давайте использовать идею заставляя его быть массивом.

def function(arg) 
    raise TypeError unless arg.is_a? Array 
    arg.each do |a| 
    puts a 
    end 
end 

Хорошо, теперь мы сделали другую ошибку, но если метод вызывается с чем-то другим, чем массив, он еще генерирует ошибку.

Кроме того, что относительно этого?

function("Hello World".chars) 

Упс, у нас есть ошибки, несмотря на то, что функция бы работала!

рубин путь будет что-то подобное:

def function(arg) 
    if arg.respond_to? :each 
    arg.each do |a| 
     puts a 
    end 
    else 
    puts arg 
    end 
end 

Теперь ваша функция работает хорошо для всех видов входов:

function([1,2,3,4]) 
function("foo") 
function("foo".chars) 

Что касается правильности функции, вы покрываете, что используя тесты, а не компилятор. Но это еще одна тема. :)

0

Вместо того, чтобы поднимать ошибку, вы можете убедиться, что вы преобразовали аргумент в массив, но вам лучше работать с процедурой, предоставляющей параметр, чтобы он дал вам массив в первую очередь.

def function(*arg) 
    a = arg.flatten 
    p a 
end 

function("ab") 
function(1,2) 
function([1,2]) 

#=> 
#["ab"] 
#[1, 2] 
#[1, 2] 
0

Если приемник в вашем примере тривиален и определяются как функция, а затем метод, то вы можете включить аргумент в приемник.

class Array 
    def function 
    # do stuff 
    end 
end 
Смежные вопросы