2014-05-20 12 views
6

Dưới đây là một số mã:Kiểm tra nếu không có đối số được truyền

$ cat 1.rb 
#!/usr/bin/env ruby 
def f p1 = nil 
    unless p1 # TODO 
     puts 'no parameters passed' 
    end 
end 
f 
f nil 
$ ./1.rb 
no parameters passed 
no parameters passed 

Câu hỏi đặt ra là, liệu có một cách để phân biệt giữa không có đối số và một nil lập luận thông qua?

UPD

tôi quyết định thêm một trường hợp sử dụng trong javascript làm cho mọi hy vọng rõ ràng hơn:

someProp: function(value) { 
    if (arguments.length) { 
     this._someProp = value; 
    } 
    return this._someProp; 
} 
+0

Nếu p1 được mặc định là không, không chuyển số không giống như không? – Cereal

+0

@Cereal Vui lòng xem câu hỏi, tôi đã thêm một trường hợp sử dụng. Vì vậy, nếu tôi không thể phân biệt giữa không có giá trị và 'nil', tôi không thể đặt giá trị của biến thành' nil'. Người ta có thể lập luận rằng tôi nên chọn giá trị mặc định khác nhau, nhưng tôi tin rằng 'nil' là giá trị thích hợp nhất trong trường hợp này. Ngoài ra, nó có thể là bạn không thể mong đợi biến để không mất một số giá trị. –

Trả lời

10

Có ba cách sử dụng chung. Một cách là sử dụng các giá trị mặc định để thiết lập một biến khác cho thấy có hay không giá trị mặc định được đánh giá:

def f(p1 = (no_argument_passed = true; nil)) 
    'no arguments passed' if no_argument_passed 
end 

f  # => 'no arguments passed' 
f(nil) # => nil 

Cách thứ hai là sử dụng một số đối tượng mà chỉ được biết đến trong các phương pháp như giá trị mặc định, do đó người ngoài là không thể chuyển đối tượng đó vào:

-> { 
    undefined = BasicObject.new 
    define_method(:f) do |p1 = undefined| 
    'no arguments passed' if undefined.equal?(p1) 
    end 
}.() 

f  # => 'no arguments passed' 
f(nil) # => nil 

Trong số hai thứ này, cái đầu tiên là thành ngữ hơn. Cái thứ hai (thực sự, một biến thể của nó) được sử dụng bên trong Rubinius, nhưng tôi chưa bao giờ gặp nó ở bất cứ nơi nào khác.

Một giải pháp thứ ba sẽ được thực hiện một số biến của tham số sử dụng biểu tượng báo:

def f(*ps) 
    num_args = ps.size 
    raise ArgumentError, "wrong number of arguments (#{num_args} for 0..1)" if num_args > 1 
    'no arguments passed' if num_args.zero? 
end 

f  # => 'no arguments passed' 
f(nil) # => nil 

Lưu ý rằng điều này đòi hỏi bạn phải tái thực hiện arity Ruby kiểm tra bằng tay. (Và chúng tôi vẫn chưa hiểu đúng, vì điều này làm tăng ngoại lệ bên trong phương pháp, trong khi Ruby sẽ tăng nó tại trang web gọi.) Nó cũng yêu cầu bạn ghi lại chữ ký phương thức của mình theo cách thủ công vì trình tạo tài liệu tự động như vậy vì RDOC hoặc YARD sẽ phỏng đoán một số tham số tùy ý thay vì một tham số tùy chọn.

+0

Cách thứ nhất nhắc tôi về 'lisp', nếu tôi không nhầm. –

+0

Vâng, tôi có thể sai, nó nhắc tôi cách xác định xem một đối số có được cung cấp hay không: '(defun foo (a b & optional (c 3 c-supplied-p)) (liệt kê a b c c-supplied-p))'. '(foo 1 2) ==> (1 2 3 NIL)', '(foo 1 2 3) ==> (1 2 3 T)', '(foo 1 2 4) ==> (1 2 4 T) '. –

5

Bạn có thể yêu cầu cho các đối số splat:

def f(*args) 
    if args.empty? 
    puts 'no parameters passed' 
    else 
    p1 = args[0] 
    ... 
    end 
end 

Một số tùy chọn khác có thể có đối tượng riêng để cho biết không có tham số nào được chuyển:

def initialize 
    @no_param_passed = Object.new 
end 

def f(p1 = @no_param_passed) 
    if p1 == @no_param_passed 
    puts 'no parameters passed' 
    end 
end 
Các vấn đề liên quan