ตรวจสอบว่าตัวแปรถูกกำหนดหรือไม่?


คำตอบ:


791

ใช้defined?คำสำคัญ ( เอกสาร ) มันจะส่งคืนสตริงที่มีชนิดของรายการหรือnilหากไม่มีอยู่

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

ในฐานะที่เป็น skalee แสดงความคิดเห็น: "มันเป็นมูลค่า noting ตัวแปรที่กำหนดให้เป็นศูนย์จะเริ่มต้น"

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

92
เป็นที่น่าสังเกตว่าตัวแปรที่ตั้งค่าให้nil ถูกเตรียมใช้งาน
skalee

7
หากคุณต้องการตั้งค่าตัวแปรหากไม่มีอยู่และปล่อยให้อยู่คนเดียวถ้ามีให้ดูที่คำตอบของ @ danmayer (เกี่ยวข้องกับ||=ผู้ดำเนินการ) ด้านล่าง
jrdioko

2
นี่คือความผิดปกติอื่น ๆ ที่ฉันสามารถทำได้ .. หากคุณกำหนดตัวแปรใน if-block ซึ่งเงื่อนไขไม่เคยเป็นไปตามนั้นdefined?ยังคงส่งกลับค่าจริงสำหรับตัวแปรที่กำหนดภายในบล็อกนั้น!
elsurudo

1
มีวิธีการdefined?ที่ส่งกลับบูลีนหรือไม่?
stevec

หากต้องการกลับ / เท็จจริง!!defined?(object_name)
stevec

91

สิ่งนี้มีประโยชน์หากคุณไม่ต้องการทำอะไรถ้ามันมีอยู่ แต่สร้างมันขึ้นมาหากไม่มีอยู่

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

สิ่งนี้จะสร้างอินสแตนซ์ใหม่เพียงครั้งเดียว หลังจากนั้นก็แค่คืนค่า var


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
นั่นไม่จำเป็นเนื่องจากไม่มีการประเมินว่าเป็นเท็จเมื่อใช้ในการทดสอบ
Jerome

ทำไมdefined?(var) == nilล่ะ
vol7ron

@ vol7ron - นั่นคือไวยากรณ์ที่ถูกต้องสมบูรณ์ การใช้สายเพื่อ.nil?เป็นสำนวนที่มากขึ้นตามที่พวกเขาพูด มันยิ่ง "เชิงวัตถุ" เพื่อถามวัตถุว่ามันnilจะใช้ตัวดำเนินการเปรียบเทียบ ไม่สามารถอ่านได้ยากดังนั้นให้ใช้วิธีใดก็ตามที่ช่วยคุณจัดส่งผลิตภัณฑ์ได้มากขึ้น
juanpaco

คุณหมายถึงคำใด?!? อย่าใช้คำตอบเป็นความคิดเห็นอย่างอื่น
Arnaud Meuret

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

คำตอบนี้เพิ่มอะไรที่ยังไม่ได้รับคำตอบจากคนอื่น?
Andrew Grimm

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?มันเป็นตัวเลือก
James

8

คำเตือน Re: รูปแบบ Ruby ทั่วไป

นี่คือคำตอบที่สำคัญ: defined?วิธีการ คำตอบที่ได้รับการยอมรับข้างต้นแสดงให้เห็นอย่างสมบูรณ์แบบนี้

แต่มีฉลามซ่อนตัวอยู่ใต้คลื่น ...

ลองพิจารณารูปแบบทับทิมสามัญประเภทนี้:

 def method1
    @x ||= method2
 end

 def method2
    nil
 end

method2nilผลตอบแทนเสมอ ครั้งแรกที่คุณโทรหา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
Andrew Grimm

การใช้unlessคำสั่งดูซับซ้อนเกินไป
johannes

5

ตัวอย่างอื่น ๆ แสดงให้เห็นว่าคุณไม่จำเป็นต้องใช้บูลีนจากวิธีการเลือกตรรกะในทับทิม มันจะเป็นรูปแบบที่ไม่ดีในการบีบบังคับทุกอย่างให้กับบูลีนเว้นแต่ว่าคุณต้องการบูลีนจริงๆ

แต่ถ้าคุณต้องการบูลีนจริงๆ ใช้ !! (bang bang) หรือ "falsy falsy เปิดเผยความจริง"

 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บล็อกจะถูกดำเนินการ

แก้ไข: สัญกรณ์ที่ถูกต้องสำหรับการตรวจสอบว่ามีกุญแจอยู่ในแฮชหรือไม่:

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และสับสนเมื่อมีการมอบหมาย / เอ่ยถึงตัวแปรในบล็อกที่ไม่ได้รับการตี
Paul Pettengill

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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.