রুবি ব্লকে 'রিটার্ন' ব্যবহার করা


89

আমি এম্বেড থাকা স্ক্রিপ্টিং ভাষার জন্য রুবি ১.৯.১ ব্যবহার করার চেষ্টা করছি, যাতে "শেষ ব্যবহারকারী" কোডটি রুবি ব্লকে লিখিত হয়। এর সাথে একটি সমস্যা হ'ল আমি চাই যে ব্যবহারকারীরা ব্লকগুলিতে 'রিটার্ন' কীওয়ার্ডটি ব্যবহার করতে সক্ষম হবেন, তাই তাদের অন্তর্নিহিত রিটার্ন মানগুলি নিয়ে চিন্তা করার দরকার নেই। এটি মনে রেখে, এই ধরণের জিনিসটি আমি করতে সক্ষম হতে চাই:

def thing(*args, &block)
  value = block.call
  puts "value=#{value}"
end

thing {
  return 6 * 7
}

আমি যদি উপরের উদাহরণটিতে 'রিটার্ন' ব্যবহার করি তবে আমি একটি লোকালজম্পআরার পাই। আমি সচেতন যে এটি কারণ, কারণ প্রশ্নে থাকা ব্লকটি একটি প্রাক এবং ল্যাম্বডা নয়। আমি 'রিটার্ন' সরিয়ে দিলে কোডটি কাজ করে তবে আমি এই দৃশ্যে 'রিটার্ন' ব্যবহার করতে সক্ষম হতে পছন্দ করব। এটা কি সম্ভব? আমি ব্লকটিকে ল্যাম্বডায় রূপান্তর করার চেষ্টা করেছি, তবে ফলাফলটি একই।


আপনি কেন অন্তর্নিহিত ফেরতের মান এড়াতে চান?
marcgg

@marcgg - - আমি এখানে একটি সম্পর্কিত প্রশ্ন আছে stackoverflow.com/questions/25953519/...
স্মিথ

উত্তর:


173

nextএই প্রসঙ্গে সহজভাবে ব্যবহার করুন :

$ irb
irb(main):001:0> def thing(*args, &block)
irb(main):002:1>   value = block.call
irb(main):003:1>   puts "value=#{value}"
irb(main):004:1> end
=> nil
irb(main):005:0>
irb(main):006:0* thing {
irb(main):007:1*   return 6 * 7
irb(main):008:1> }
LocalJumpError: unexpected return
        from (irb):7:in `block in irb_binding'
        from (irb):2:in `call'
        from (irb):2:in `thing'
        from (irb):6
        from /home/mirko/.rvm/rubies/ruby-1.9.1-p378/bin/irb:15:in `<main>'
irb(main):009:0> thing { break 6 * 7 }
=> 42
irb(main):011:0> thing { next 6 * 7 }
value=42
=> nil
  • return সর্বদা পদ্ধতি থেকে ফিরে আসে, তবে আপনি যদি এই স্নিপেটটি আইআরবিতে পরীক্ষা করেন তবে আপনার পদ্ধতি নেই, সেই কারণেই আপনার রয়েছে LocalJumpError
  • breakব্লক থেকে মান ফেরত দেয় এবং তার কলটি শেষ করে। যদি আপনার ব্লকটি দ্বারা yieldবা ডেকে আনা হয়েছিল .call, তবে breakএই পুনরুক্তিকারী থেকেও বিরতি
  • nextব্লক থেকে মান ফেরত দেয় এবং তার কলটি শেষ করে। যদি আপনার ব্লকটি দ্বারা yieldবা ডাকা হত .call, তবে nextযেখানে yieldডাকা হত সেই লাইনে মান ফেরত দেয়


আপনি যে "ব্লক থেকে পরবর্তী রিটার্নের মান এবং এটি কলটি শেষ করে" থেকে এই তথ্যটি পাবেন সেখানে আপনি উদ্ধৃতি দিতে পারেন? আমি এটি আরও পড়তে চাই।
ব্যবহারকারী566245

যদি আমি সঠিকভাবে মনে রাখি তবে এটি রুবি প্রোগ্রামিং ল্যাঙ্গুয়েজ বইটি থেকে ছিল (এখনই এটি হাতে নেই)। আমি কেবল গুগল চেক করেছি এবং আমি বিশ্বাস করি যে এটি সেই বইটি থেকে এসেছে: লাইব্রেরি.আইম্মেটারিয়েল.ফ.আর / ফ্রি / পড়া_বইক / 97৮০5965৫16১16১8৮ / ২ এবং সেখান থেকে পরবর্তী দুটি পৃষ্ঠা (এটি আমার বিষয়বস্তু এবং আমার পৃষ্ঠাগুলি নয়, আমি কেবল এটি গুগল করেছি)। তবে আমি সত্যিই মূল বইয়ের প্রস্তাব দিচ্ছি, এতে আরও অনেক রত্ন ব্যাখ্যা করা আছে।
এমবিও

এছাড়াও আমি আমার মাথা থেকে উত্তর দিয়েছি, কেবল আইআরবিতে জিনিসগুলি পরীক্ষা করে দেখছি, এ কারণেই আমার উত্তরটি প্রযুক্তিগত বা সম্পূর্ণ নয়। আরও তথ্যের জন্য রুবি প্রোগ্রামিং ভাষার বইটি দেখুন।
এমবিও

আমি আশা করি এই উত্তরটি শীর্ষে ছিল। আমি এটি যথেষ্ট upvote করতে পারবেন না।
বিটিএক্স 9000

20

আপনি রুবিতে এটি করতে পারবেন না।

মূল returnশব্দটি সর্বদা বর্তমান প্রসঙ্গে পদ্ধতি বা ল্যাম্বদা থেকে ফিরে আসে। ব্লকগুলিতে, এটি সেই পদ্ধতি থেকে ফিরে আসবে যেখানে বন্ধের সংজ্ঞা দেওয়া হয়েছিল । কলিং পদ্ধতি বা ল্যাম্বদা থেকে ফিরে আসা যায় না ।

Rubyspec প্রমান করে যে এই সত্যিই রুবি জন্য সঠিক আচরণ (বোঝা যাচ্ছে যে নেতারা না একটি বাস্তব বাস্তবায়ন কিন্তু লক্ষ্য সি রুবি সঙ্গে পূর্ণ সামঞ্জস্য) হল:

describe "The return keyword" do
# ...
describe "within a block" do
# ...
it "causes the method that lexically encloses the block to return" do
# ...
it "returns from the lexically enclosing method even in case of chained calls" do
# ...

সেখানে একটি ব্লক জন্য / proc থেকে ফিরে উপর একটি বিস্তারিত প্রবন্ধ আছে এখানে
ComDubh

3

আপনি এটিকে ভুল দৃষ্টিকোণ থেকে দেখছেন। এটি thingল্যাম্বডা নয়, একটি বিষয় ।

def thing(*args, &block)
  block.call.tap do |value|
    puts "value=#{value}"
  end
end

thing {
  6 * 7
}

1

কোথা থেকে জিনিস চাওয়া হয়? আপনি কি একটি ক্লাসের ভিতরে আছেন?

আপনি এই জাতীয় কিছু ব্যবহার বিবেচনা করতে পারেন:

class MyThing
  def ret b
    @retval = b
  end

  def thing(*args, &block)
    implicit = block.call
    value = @retval || implicit
    puts "value=#{value}"
  end

  def example1
    thing do
      ret 5 * 6
      4
    end
  end

  def example2
    thing do
      5 * 6
    end
  end
end

1

রুবিতে ওয়েব ফ্রেমওয়ার্কের জন্য ডিএসএল লেখার ক্ষেত্রে আমার একই সমস্যা ছিল ... (ওয়েব ফ্রেম ফ্রেমটি অ্যানোরিক্সিক রক করবে!) ...

যাইহোক, আমি রুবি ইন্টারনালগুলির মধ্যে খনন করেছি এবং লোকালজ্যাম্পেরার ব্যবহার করে একটি সহজ সমাধান পেয়েছি যখন কোনও প্রস ডাকার ডাক দেয় ... এটি এখন পর্যন্ত পরীক্ষাগুলিতে ভাল চলে, তবে আমি নিশ্চিত নই যে এটি পুরো-প্রমাণ রয়েছে:

def thing(*args, &block)
  if block
    block_response = nil
    begin
      block_response = block.call
    rescue Exception => e
       if e.message == "unexpected return"
          block_response = e.exit_value
       else
          raise e 
       end
    end
    puts "value=#{block_response}"
  else
    puts "no block given"
  end
end

উদ্ধার বিভাগে যদি বিবৃতি সম্ভবত কিছু দেখতে পারে:

if e.is_a? LocalJumpError

তবে এটি আমার জন্য অনির্ধারিত অঞ্চল, তাই আমি এখন পর্যন্ত যা পরীক্ষা করেছি তার সাথে আমি আঁকড়ে থাকব।


1

আমি বিশ্বাস করি যে এই ত্রুটিগুলি সত্ত্বেও এটি সঠিক উত্তর:

def return_wrap(&block)
  Thread.new { return yield }.join
rescue LocalJumpError => ex
  ex.exit_value
end

def thing(*args, &block)
  value = return_wrap(&block)
  puts "value=#{value}"
end

thing {
  return 6 * 7
}

এই হ্যাক ব্যবহারকারীদের তাদের প্রক্সগুলিতে ফলাফল ছাড়াই রিটার্ন ব্যবহার করতে দেয়, স্ব সংরক্ষণ করা হয় ইত্যাদি without

থ্রেড এখানে ব্যবহার করার সুবিধাটি হ'ল কিছু ক্ষেত্রে আপনি লোকালজম্পেরার পাবেন না - এবং প্রত্যাবর্তনটি সবচেয়ে অপ্রত্যাশিত জায়গায় ঘটবে (একটি শীর্ষ-স্তরের পদ্ধতির পাশে, অপ্রত্যাশিতভাবে তার শরীরের বাকি অংশটি এড়িয়ে যাওয়া)।

প্রধান অসুবিধা হ'ল সম্ভাব্য ওভারহেড (আপনি থ্রেড + প্রতিস্থাপন করতে পারেন যদি আপনার দৃশ্যে yieldযথেষ্ট হয় তবে) join


1

আমি একটি উপায় খুঁজে পেয়েছি, তবে এর মধ্যে একটি পদ্ধতির মধ্যবর্তী পদক্ষেপ হিসাবে সংজ্ঞা দেওয়া জড়িত:

def thing(*args, &block)
  define_method(:__thing, &block)
  puts "value=#{__thing}"
end

thing { return 6 * 7 }
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.