Khi làm việc với các method
trong ruby
, các bạn có thể gặp các trường hợp tham số được định nghĩa trong method
sẽ có dạng: *args
, **kwargs
, &block
, … Vậy chúng là gì, hôm nay ta sẽ tìm hiểu về vấn đề này thông qua ruby method parameters
Default parameters
- Khi định nghĩa một
method
, ta có thể chỉ ra giá trịdefault
(mặc định) cho chúng. Khimethod
được gọi, nếu các giá trịarguments
(đổi số) ít hơn những giá trịparameters
(tham số) được khai báo trước đó thì những tham số mặc định sẽ sử dụng những giá trị được gán mặc định đó.123456789<span class="token keyword">def</span> <span class="token method-definition"><span class="token function">info</span></span><span class="token punctuation">(</span>name<span class="token punctuation">,</span> sex<span class="token operator">=</span><span class="token string">"male"</span><span class="token punctuation">)</span>puts <span class="token string">"Name: <span class="token interpolation"><span class="token delimiter tag">#{</span>name<span class="token delimiter tag">}</span></span>, with sex: <span class="token interpolation"><span class="token delimiter tag">#{</span>sex<span class="token delimiter tag">}</span></span>"</span><span class="token keyword">end</span>info<span class="token punctuation">(</span><span class="token string">"huy"</span><span class="token punctuation">,</span> <span class="token string">"female"</span><span class="token punctuation">)</span><span class="token comment"># => Name: huy, with sex: female</span>info<span class="token punctuation">(</span><span class="token string">"huy"</span><span class="token punctuation">)</span><span class="token comment"># => Name: huy, with sex: male</span> - Nếu trong định nghĩa
method
có nhiều hơn mộtdefault parameter
thì nhữngparameters
này phải được đặt liền kề nhau. Ví dụ, không thể đặt mộtparameter
khác nằm giữa haidefault parameter
được. method
có nhiều hơn mộtdefault parameter
khi được thực thi với một danh sách cácarguments
được truyền vào, thì nhữngarguments
này sẽ được gắn giá trị cho cácdefault parameters
từ trái sang phải:1234567891011<span class="token keyword">def</span> <span class="token method-definition"><span class="token function">f</span></span><span class="token punctuation">(</span>a<span class="token punctuation">,</span> b<span class="token operator">=</span><span class="token number">1</span><span class="token punctuation">,</span> c<span class="token operator">=</span><span class="token number">2</span><span class="token punctuation">)</span>puts a<span class="token punctuation">,</span> b<span class="token punctuation">,</span> c<span class="token keyword">end</span>f<span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">)</span><span class="token comment"># => 10, 1, 2</span>f<span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">,</span> <span class="token number">100</span><span class="token punctuation">)</span><span class="token comment"># => 10, 100, 2</span>f<span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">,</span> <span class="token number">100</span><span class="token punctuation">,</span> <span class="token number">200</span><span class="token punctuation">)</span><span class="token comment"># => 10, 100, 200</span>
Parameter with splat operator (*)
- Tham số kiểu mảng được gắn dấu
*
phía trước được sử dụng khi muốn truyền một mảng các đối số bất kỳ:1234567<span class="token keyword">def</span> <span class="token method-definition"><span class="token function">f</span></span><span class="token punctuation">(</span>first<span class="token punctuation">,</span> <span class="token operator">*</span>rest<span class="token punctuation">)</span>puts rest<span class="token punctuation">,</span> rest<span class="token punctuation">.</span><span class="token keyword">class</span><span class="token class-name">end</span>f<span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">)</span><span class="token comment"># => [2, 3, 4], Array</span> - Một
method
có không quá một tham số loại này, tham số kiểu mảng phải theo liền kề sau những tham số mặc định, và có thể đứng trước các tham số bình thường khác:1234567<span class="token keyword">def</span> <span class="token method-definition"><span class="token function">f</span></span><span class="token punctuation">(</span>a<span class="token operator">=</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token operator">*</span>args<span class="token punctuation">,</span> b<span class="token punctuation">)</span>puts <span class="token string">"a: <span class="token interpolation"><span class="token delimiter tag">#{</span>a<span class="token delimiter tag">}</span></span>, args: <span class="token interpolation"><span class="token delimiter tag">#{</span>args<span class="token delimiter tag">}</span></span>, b: <span class="token interpolation"><span class="token delimiter tag">#{</span>b<span class="token delimiter tag">}</span></span>"</span><span class="token keyword">end</span>f<span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">,</span> <span class="token number">20</span><span class="token punctuation">,</span> <span class="token number">30</span><span class="token punctuation">,</span> <span class="token number">40</span><span class="token punctuation">)</span><span class="token comment"># => a: 10, args: [20, 30], b: 40</span> - Ngoài ra,
*
còn được sử dụng khi ta muốn truyền một mảng các đối số khi gọimethod
:
1 2 3 4 5 6 7 8 | <span class="token keyword">def</span> <span class="token method-definition"><span class="token function">f</span></span><span class="token punctuation">(</span>name<span class="token punctuation">,</span> age<span class="token punctuation">,</span> sex<span class="token punctuation">)</span> puts name<span class="token punctuation">,</span> age<span class="token punctuation">,</span> sex <span class="token keyword">end</span> user <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">"sherlock"</span><span class="token punctuation">,</span> <span class="token number">20</span><span class="token punctuation">,</span> <span class="token string">"male"</span><span class="token punctuation">]</span> f<span class="token punctuation">(</span><span class="token operator">*</span>user<span class="token punctuation">)</span> <span class="token comment"># => sherlock, 20, male</span> |
Mapping arguments to parameters
Ta sẽ tìm hiểu cách ruby
gán các đối số được truyền tới các tham số đã được định nghĩa trong method
.
Giả sử một method
có o
tham số original
(tham số thường), d
tham số được gán giá trị mặc định, 1 tham số kiểu mảng. method
được gọi với a
đối số, khi đó:
- Nếu
a < o
: lỗiArgumentError
xảy ra - Nếu
o <= a <= o+d
:a-o
tham số mặc định sẽ được gán giá trị, phần còn lại,o+d-a
tham số mặc định sẽ sử dụng giá trị mặc định ban đầu. - Nếu
a > o+d
:a-o-d
đối số được truyền vào sẽ gán cho tham số mảng cuối cùng
Using hash for named arguments
Khi một method
yêu cầu nhiều hơn 2 hoặc 3 tham số sẽ rất khó trong việc thực thi method
này, ta cần phải nhớ hết thứ tự của tất cả các tham số này khi truyền các đối số vào. Đễ giải quyết vấn đề này, trong ruby
ta có thể sử dụng hash argument
:
1 2 3 4 5 6 7 | <span class="token keyword">def</span> <span class="token method-definition"><span class="token function">f</span></span><span class="token punctuation">(</span>opts<span class="token punctuation">)</span> puts opts <span class="token keyword">end</span> f<span class="token punctuation">(</span><span class="token punctuation">{</span>name<span class="token punctuation">:</span> <span class="token string">"huy"</span><span class="token punctuation">,</span> age<span class="token punctuation">:</span> <span class="token number">11</span><span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token comment"># => {:name=>"huy", :age=>11}</span> |
- Nếu trong
method
tham số dạng hash nằm ở cuối cùng (hoặc theo sau nó là mộtblock
), ta có thể bỏ qua dấu{}
khi gọimethod
đó:123f<span class="token punctuation">(</span>name<span class="token punctuation">:</span> <span class="token string">"huy"</span><span class="token punctuation">,</span> age<span class="token punctuation">:</span> <span class="token number">11</span><span class="token punctuation">)</span><span class="token comment"># => {:name=>"huy", :age=>11}</span>
Parameter with double splat (**) operator
Một cách nữa để khai báo tham số kiểu hash: dùng **
:
1 2 3 4 5 6 7 8 9 10 | <span class="token keyword">def</span> <span class="token method-definition"><span class="token function">f</span></span><span class="token punctuation">(</span><span class="token operator">*</span><span class="token operator">*</span>hash<span class="token punctuation">)</span> puts hash <span class="token keyword">end</span> f<span class="token punctuation">(</span>a<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">,</span> b<span class="token punctuation">:</span> <span class="token number">2</span><span class="token punctuation">)</span> <span class="token comment"># => {:a=>1, :b=>2}</span> f<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment"># Nếu không truyền đối số nào, mặc định cho `hash` sẽ là `{}`</span> <span class="token comment"># => {}</span> |
Block arguments with (&)
- Một
block
có thể được truyền vào khi gọimethod
:1234567<span class="token keyword">def</span> <span class="token method-definition"><span class="token function">f</span></span><span class="token punctuation">(</span>name<span class="token punctuation">,</span> <span class="token operator">&</span>block<span class="token punctuation">)</span><span class="token keyword">yield</span> name<span class="token keyword">end</span>f<span class="token punctuation">(</span><span class="token string">"sherlock"</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token operator">|</span>name<span class="token operator">|</span> puts name <span class="token punctuation">}</span><span class="token comment"># => sherlock</span>
Nếu trong danh sách tham số không có&
,block
vẫn có thể được truyền vào qua{}
hoặcdo; ;end
- Lưu ý rằng tham số với
&
chỉ được định nghĩa một lần duy nhất, và nó phải được đặt ở vị trí cuối cùng trong danh sách:
1 2 3 4 5 6 7 8 9 10 11 | <span class="token keyword">def</span> <span class="token method-definition"><span class="token function">f</span></span><span class="token punctuation">(</span><span class="token operator">&</span>block<span class="token punctuation">,</span> <span class="token operator">&</span>other_block<span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span> <span class="token keyword">end</span> <span class="token comment"># => syntax error, unexpected ',', expecting ')'</span> <span class="token keyword">def</span> <span class="token method-definition"><span class="token function">f</span></span><span class="token punctuation">(</span><span class="token operator">&</span>block<span class="token punctuation">,</span> name<span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span> <span class="token keyword">end</span> <span class="token comment"># => syntax error, unexpected ',', expecting ')'</span> |