Перевірка, чи визначена змінна?


Відповіді:


791

Використовуйте defined?ключове слово ( документація ). Він поверне рядок із типом елемента або nilякщо його не існує.

>> a = 1
 => 1
>> defined? a
 => "local-variable"
>> defined? b
 => nil
>> defined? nil
 => "nil"
>> defined? String
 => "constant"
>> defined? 1
 => "expression"

Як коментує skalee: "Варто зазначити, що змінна, яка встановлена ​​на нуль, ініціалізується".

>> n = nil  
>> defined? n
 => "local-variable"

92
Варто зазначити, що змінна, для якої встановлено nil , ініціалізується.
— skalee

7
Якщо ви хочете встановити змінну, якщо вона не існує, і залишити її в спокої, якщо вона є, дивіться відповідь @ danmayer (за участю ||=оператора) нижче.
— jrdioko

2
Ось ще одна дивовижність, на яку я можу ввійти. Якщо ви визначаєте змінну в блоці if, для якої умова ніколи не виконується, defined?все одно повертається true для змінної, визначеної в цьому блоці!
— elsurudo

1
Чи є такий метод, defined?що повертає булевий?
— stevec

Щоб повернути істина / неправда,!!defined?(object_name)
— stevec

91

Це корисно, якщо ви не хочете нічого робити, якщо він існує, але створити його, якщо його немає.

def get_var
  @var ||= SomeClass.new()
end

Це створює новий екземпляр лише один раз. Після цього він просто продовжує повертати вар.


9
Це дуже ідіоматичний Рубі теж, до речі.
— jrdioko

38
Просто не використовуйте ||=булеві значення, щоб не відчути біль розгубленості.
— Ендрю Маршалл

6
разом з тим, що сказав @AndrewMarshall, уникайте цієї ідіоми з будь-чим, що може також повернутися nil, якщо ви дійсно не хочете оцінювати вираз кожен раз, коли воно викликане, коли воно повертаєтьсяnil
— nzifnab

1
Якщо будуть працювати з Булевой, і щоб значення за замовчуванням , щоб бути правдою , якщо змінна чітко зазначених БРЕХНЯ, ви можете використовувати цю конструкцію: var = (var or var.nil?)
— Тоні Сито

1
@ArnaudMeuret Сорт, не дуже. - хоча це може здатися ідентичним, варто прочитати відповіді на це питання.
— Фонд позову Моніки

70

Правильний синтаксис для наведеного вище твердження:

if (defined?(var)).nil? # will now return true or false
 print "var is not defined\n".color(:red)
else
 print "var is defined\n".color(:green)
end

заміщення ( var) вашою змінною. Цей синтаксис поверне справжнє / хибне значення для оцінки в операторі if.


11
Це не обов'язково, оскільки нуль оцінюється як хибне при використанні в тесті
— Джеронім

Чому ні defined?(var) == nil?
— vol7ron

@ vol7ron - Це абсолютно правильний синтаксис. .nil?Як говорять, використання дзвінка до більш ідіоматичного. Більш "об'єктно-орієнтований" запитувати об'єкт, якщо він, nilніж використовувати оператор порівняння. Читати це не складно, тому використання того, що допоможе вам доставити більше товару.
— juanpaco

До якої заяви ви посилаєтесь?!? Не використовуйте відповідь як коментар до чогось іншого.
— Арно Меурет

18

defined?(your_var)буду працювати. Залежно від того, що ви робите, ви можете зробити щось подібнеyour_var.nil?


+1, your_var.nil?тому що він повертає істинне помилкове значення і набагато приємніше читати і писати, ніж defined? var. Дякую за це
— kakubei

28
your_var.nil?призведе до помилки: undefined local variable or method your_varколи не визначено раніше ...
— Gobol

16

Спробуйте "якщо" замість "якщо"

a = "apple"
# Note that b is not declared
c = nil

unless defined? a
    puts "a is not defined"
end

unless defined? b
    puts "b is not defined"
end

unless defined? c
    puts "c is not defined"
end

Що додає ця відповідь, що не було сказано в інших відповідях?
— Ендрю Грімм

2
Це дуже добре відповідає на питання ще одним корисним способом, чи не так?
— дивіться

2
Посібник зі стилю в рубіні говорить "Віддавайте перевагу хіба що за негативних умов" github.com/bbatsov/ruby-style-guide
— ChrisPhoenix


8

Ось якийсь код, нічого ракетного науки, але він працює досить добре

require 'rubygems'
require 'rainbow'
if defined?(var).nil?  # .nil? is optional but might make for clearer intent.
 print "var is not defined\n".color(:red)
else
 print "car is defined\n".color(:green)
end

Зрозуміло, що забарвлення коду не обов’язкова, просто приємна візуалізація в цьому прикладі іграшки.


Імовірно, тому що nil?необов'язковий.
— Джеймс

8

ПОПЕРЕДЖЕННЯ Щодо: загального рубінового малюнка

Це ключова відповідь: defined?метод. Прийнята вище відповідь чудово ілюструє це.

Але є акула, яка ховається під хвилями ...

Розглянемо цей тип загального рубінового малюнка:

 def method1
    @x ||= method2
 end

 def method2
    nil
 end

method2завжди повертається nil. Перший раз, коли ви телефонуєте method1, @xзмінна не встановлюється - тому method2буде запущена. і method2встановить @xдо nil. Це добре, і все добре і добре. Але що відбувається вдруге, коли ви телефонуєте method1?

Пам'ятайте, що @x вже встановлено на нуль. But method2все одно буде запущений знову !! Якщо method2 є дорогим завданням, це може бути не те, що ви хочете.

Нехай defined?метод приходить на допомогу - при цьому вирішується конкретний випадок - використовуйте наступне:

  def method1
    return @x if defined? @x
    @x = method2
  end

Чорт у деталях: але ви можете уникнути цієї ховаючої акули defined?методом.


Ви абсолютно праві, дякую, що підкреслили той конкретний застереження
— Кулгар

5

Ви можете спробувати:

unless defined?(var)
  #ruby code goes here
end
=> true

Тому що це повертає булеву форму.


SyntaxError: compile error (irb):2: syntax error, unexpected $end, expecting kEND
— Ендрю Грімм

використовувати unlessзаяву здається надмірно складним
— johannes

5

Як багато інших прикладів показують, що насправді не потрібно булевого методу, щоб зробити логічний вибір у рубіні. Це було б поганою формою, щоб примусити все до булевого, якщо вам насправді не потрібно булеве.

Але якщо вам абсолютно потрібен бул. Використовуйте !! (брехливий вибух) або "фальшивий фальш розкриває правду".

› irb
>> a = nil
=> nil
>> defined?(a)
=> "local-variable"
>> defined?(b)
=> nil
>> !!defined?(a)
=> true
>> !!defined?(b)
=> false

Чому зазвичай не платять примусово:

>> (!!defined?(a) ? "var is defined".colorize(:green) : "var is not defined".colorize(:red)) == (defined?(a) ? "var is defined".colorize(:green) : "var is not defined".colorize(:red))
=> true

Ось приклад, де це має значення, оскільки воно покладається на неявну примус булевого значення до його рядкового подання.

>> puts "var is defined? #{!!defined?(a)} vs #{defined?(a)}"
var is defined? true vs local-variable
=> nil

3

Слід зазначити, що використання definedдля перевірки, чи певне поле встановлено в хеші, може вести себе несподівано:

var = {}
if defined? var['unknown']
  puts 'this is unexpected'
end
# will output "this is unexpected"

Синтаксис тут правильний, але defined? var['unknown']буде оцінено як рядок "method", томуif блок буде виконаний

edit: Правильне позначення для перевірки наявності ключа в хеші було б:

if var.key?('unknown')

2

Зверніть увагу на відмінність "визначеного" та "призначеного".

$ ruby -e 'def f; if 1>2; x=99; end;p x, defined? x; end;f'
nil
"local-variable"

x визначено, хоча він ніколи не призначається!


Це те, що я щойно натрапив. Я очікував NameError Exception: undefined local variable or methodі розгубився, коли єдине призначення / згадка змінної було в блоці if, який не потрапляв.
— Пол Петтенгілл

0

Крім того, ви можете перевірити, чи визначено це в рядку за допомогою інтерполяції, якщо ви кодуєте:

puts "Is array1 defined and what type is it? #{defined?(@array1)}"

Система підкаже вам тип, якщо він визначений. Якщо він не визначений, він просто поверне попередження про те, що змінна не ініціалізується.

Сподіваюся, це допомагає! :)


0

defined?це чудово, але якщо ви перебуваєте в середовищі Rails, ви також можете користуватися try, особливо у випадках, коли ви хочете перевірити ім'я динамічної змінної:

foo = 1
my_foo = "foo"
my_bar = "bar"
try(:foo)        # => 1
try(:bar)        # => nil
try(my_foo)      # => 1
try(my_bar)      # => nil
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.