4-3 Tạo lệnh

4-3 Tạo lệnh

Cho đến nay chúng ta chỉ dùng những lệnh đã được chuẩn bị từ trước. Tuy nhiên, chúng ta cũng có thể tự mình tạo lệnh. Nghe là tạo lệnh thì có vẻ to tát lắm nhưng thực chất chúng ta có thể dễ dàng thực hiện được nó

Định nghĩa lệnh

Hãy nhìn chương trình dưới đây.

def puts_hello
  puts hello
end

puts_hello

Nếu thực hành chạy chương trình này thì chúng ta có chữ [Hello] được hiển thị.

Hello

Trong ví dụ trên thì chúng ta đã tạo một lệnh đặt tên là [puts_hello]. Trong thế giới lập trình thì công việc tạo lệnh đó chính là công việc định nghĩa lệnh. Có nghĩa là trong chương trình ví dụ trên, chúng ta đã định nghĩa lệnh [puts_hello], sau đó chạy lệnh [puts_hello]

Dể định nghĩa lệnh [puts_hello] chúng ta dùng 3 dòng

def puts_hello
  puts "Hello"
end

Như thế lệnh [puts_hello] đã được tạo thành. Chúng ta viết tên lệnh sau [def]. Tiếp theo cuối lệnh, chúng ta kết thúc bằng end.

def tên lệnh
  Những xử lý mà lệnh sẽ thực hiện
  ...
  ...
end

Tại tên lệnh thì chúng ta có thể dung chữ cái Alphabet, chữ số và dấu gạch dưới để đặt tên. Tuy nhiên, chúng ta không thể đặt chữ số ở đầu tên. Về những chữ cái có thể sử dụng làm tên lệnh các bạn hãy tham khảo ở phần [Những chữ cái sử dụng được để đặt tên lệnh] dưới đây.

Những chữ cái dùng để đặt tên lệnh

Những kí tự có thể được dùng để đặt tên cho lệnh đó là chữ cái Alphabet, chữ số và dấu gạch dưới. Tuy nhiên ở cuối tên chúng ta có thể đặt dấu [?] hoặc dấu [!]. Từ trước đến nay luôn có thói quen, những lệnh mà giá trị trả về là [true] hay [false] thì cuối tên lệnh đều có dấu [?]. Mặt khác những lệnh để viết lại nội dung Object thì cuối câu lệnh thường có dấu [!].

Gọi lệnh

Nếu chúng ta chỉ định nghĩa lệnh thì cũng không thể thực hiện được. Để thực hiện thì chúng ta cần gọi lệnh đã định nghĩa ra.

def puts_hello	# định nghĩa lệnh puts_hello
  puts "Hello"	# khi định nghĩa thì lệnh không được chạy
end

puts_hello	    # gọi lệnh

Khi dòng cuối cùng [puts_hello] được thực hiện thì lần đầu tiên lệnh được định nghĩa bắt đầu chạy lệnh [puts] và "Hello" được hiển thị.

Trước khi chạy lệnh thì chúng ta cần phải định nghĩa nó

puts_hello	    # Lệnh chưa được định nghĩa nên lỗi

def puts_hello	# Định nghĩa lệnh
  puts "Hello"
end

Như trên nếu chúng ta gọi lệnh trước khi nó được định nghĩa thì lệnh sẽ lỗi.

Lệnh nhận argument

def puts_hello_name(name)
  print "Xin chào,"
  puts name
end

puts_hello_name("Tarou")

[Kết quả hiển thi]

Xin chào, Tarou

Lệnh [puts_hello_name] chính là lệnh nhận 1 argument. Chúng ta định nghĩa ngay sau [puts_hello_name] sẽ nhận một argument ở bộ phận (name). Giá trị argument được đưa cho, được biểu thị bằng biến số name và được sử dụng trong câu lệnh.

Name nhận được cứ như vậy được đưa ra bởi lệnh [puts] nên cứ argument nào mà lệnh puts có thể đưa ra thì hoàn toàn có thể được chấp nhận. Chúng ta hãy thử đưa vào một vài những argument khác nhau.

puts_hello_name("Paul")
puts_hello_name("ABC")
puts_hello_name(12345)

[Kết quả hiển thị]

Xin chào, Paul
Xin chào, ABC
Xin chào, 12345

Lệnh nhận những argument phức tạp hơn

Để định nghĩa lệnh nhận argument thì 2 trở lên thì chúng ta cần phân biệt những tên biến số phân biệt bằng dấu phẩy [,]

def phepcong(a, b, c)
  puts a + b + c
end

phepcong(1,2,3)

[Kết quả hiển thị]

7

Argument mặc định

Trong những lệnh chúng ta dùng cho đến nay thì đã có những lệnh đã được lược phần argument. Những phần có thể lược argument là những trường hợp đã được xác lập giá trị mặc định vào argument. Nếu chúng ta thiết lập giá trị mặc định cho argument thì khi gọi lệnh chúng ta có thẻ giản lược phần đầu vào.

Để thiết lập argument mặc định, chúng ta làm như sau.

def phepcong(a, b=0, c=0)
  puts a + b + c
end

Như ví dụ ở trên, đối với những biến [b,c] thì chúng ta đã thiết lập giá trị mặc định là 0. Khi gọi lệnh ra để thực hiện, lệnh sẽ sử dụng những giá trị trao cho, còn những giá trị không được trao cho thì lệnh sẽ tự động sử dụng giá trị mặc định.

def phepcong(a,b=0,c=0)
  puts a + b + c
end

phepcong(1)		# => 1
phepcong(1,2)	  # => 3
phepcong(1,2,3)	# => 6

Như vậy chúng ta có thể giản lược đầu vào mà lệnh vẫn được thực hiện. Trong trường hợp định nghĩa những lệnh sử dụng argument mặc định, sau argument được thiết lập mặc định thì chúng ta không thể đặt được giá trị không được thiết lập mặc định.

def phepcong(a, b=0, c)
  puts a + b + c
end

Ở ví dụ trên, giá trị [b] đã được thiết lập mặc định mà giá trị [c] đằng sau không được thiết lập. Cách định nghĩa lệnh như thế này sẽ trở thành lỗi nên mọi người hãy chú ý.

Trả lại kết quả trả về

Tính đến những lệnh đã sử dụng cho đến nay, đã có những lệnh để trả lại giá trị. Ví dụ như lệnh [size] trong dãy. Code tiếp theo đây sẽ dùng lệnh [size] để gái trị trả về là 3.

nums = [1,2,3]
p nums.size	# => 3

Những lệnh để trả lại giá trị như thế này được goi là giá trị trở về của lệnh.

Chúng ta định nghĩa sử dụng [return]. Nếu viết giá trị sau [return] thì nó sẽ trở thành giá trị trả về.

def phepcong(a,b,c)
  total = a + b + c
  return total
end

t = phepcong(1,2,4)
puts t

[Kết quả hiển thị]

7

Lệnh [phepcong] lấy giá trị trả về là tổng 3 giá trị có trong dãy số. Sau đó giá trị trả về đó được thay thế bởi biến số t và đưa ra bởi puts.

Nếu chúng ta thực hiện [return] trong lệnh thì tại đó, xủ lý trong lệnh sẽ dừng. Những xử lý được viết sau return sẽ không được thực hiện.

def phepcong(a,b,c)
  total = a + b + c
  puts "Được hiển thị"
  return total
  puts "Không được hiển thị"
end

t = phepcong(1,2,4)
puts t

[Kết quả hiển thị]

Được hiển thị
7

Giản lược return

Chúng ta cũng có thể giản lược lệnh return.

def phepcong(a,b,c)
  total = a + b + c
  total
end

Trong trường hợp giản lược [return], thì giá trị cuối lệnh sẽ tự động trở thành giá trị trả về Nếu chúng ta xóa dòng total ở cuối lệnh thì sẽ trở nên như thế nào?

def phepcong(a,b,c)
  total = a + b + c
end

Thực ra trên thực tế thì sẽ xảy ra một động tác giống nhau. Kết quả tổng [a+b+c] sẽ được đưa vào biến số [total] rồi từ biến này sẽ trả về giá trị. Chúng ta hãy thử tưởng tượng trạng thái mà [return] được viết ngay trước total (bên trái). Hơn nữa chúng ta cùng có thể lược cả [total]

def phepcong(a,b,c)
  a + b + c
end

[a+b+c] không được thay thế với biến số nhưng phép cộng vẫn được xử lý và kết quả [a+b+c] vẫn được [return]. Như tiếp theo đây, mọi người hãy tưởng tượng [return] được cho vào một cách tự động thì sẽ dễ hiểu hơn.

def phepcong(a,b,c)
  return a + b + c
end

Đưa lệnh cho lệnh

Trong argument của lệnh thì ta thường trao cho những giá trị như giá trị số, dãy chữ hay biến số, nhưng ngoài ra thì chúng ta cũng có thể trao cả lệnh. Đây là chương trình ví dụ lúc trước.

def phepcong(a,b,c)
  a + b + c
end

t = phepcong(1,2,4)
puts t

Chúng ta giản lược biến số trong chương trình như dưới đây, chúng ta giản lược rồi gọi lệnh ra trong 1 dòng thì cũng sẽ xảy ra những xử lý tương tự.

def phepcong(a,b,c)
  a + b + c
end

puts phepcong(1,2,4)

Như vậy chúng ta cũng có thể trực tiếp đưa lệnh [phepcong] cho lệnh puts. Vậy trình tự thực hiện sẽ là, đầu tiên argument của lệnh puts là lệnh [phepcong] sẽ được thực hiện, sau đó kết quả trả về của lệnh [phepcong] sẽ là đầu vào của lệnh [puts] và puts được thực hiện.

Phạm vi của biến số

Biến số có một thứ gọi là phạm vi. Phạm vi có nghĩa là phạm vi mà biến số đó vẫn còn có hiệu lực và người ta sử dụng biến số trong vòng hiệu lực đó. Hãy nhìn chương trình dưới đây.

def foo
  a = 1
  p a
end

a = 0
foo
p a

[Kết quả hiển thị]

1
0

Biến số a được sử dụng cả trong lẫn ngoài. Cả hai cái đều là biến số tên là a, nhưng [a] trong lệnh và [a] ngoài lệnh là hai a hoàn toàn khác nhau. Nhìn vào kết quả sau khi chạy lệnh chúng ta có thể hiểu được. [a] trong lệnh đại diện cho 1, nhưng hiển thị [a] ngoài lệnh thì nó vẫn là 0 Đây là vì phạm vi hiệu lực của biến số trong và ngoài là khác nhau. Phạm vi hiệu lực khác nhau thì người ta gọi là phạm vi khác nhau (Scope khác nhau). Phía bên trong lệnh được bao bởi [def~end] chính là phạm vi đặc biệt chỉ của biến số trong lệnh đó thôi.

Như dưới đây, chúng ta hãy làm rõ biến số trong và ngoài lệnh.

def foo
  p a	# => lỗi
end

a = 0	# thay 0 vào biến số a
foo	  # gọi lệnh ra

Ngược lại với lệnh ở trên chúng ta có lệnh bên dưới khi biến số bên trong lệnh thành biến số lên ngoài lệnh.

def foo
  a = 0	# thay giá trị vào biến a
end

foo	    # gọi lệnh
p a	    # => lỗi

Những biến số ta dùng từ trước đến nay thì gọi là biến local

Ngoài biến local thì chúng ta còn có biến số gọi là biến global. Biến global là biến mà đầu tên có thêm kí hiệu $

a = 0	 # biến local
$a = 0	# biến global

Biến global có phạm vi rộng hơn, ngay cả bên trong hay ngoài lệnh cũng có thể cùng giá trị.

def foo
  p$a	 # => không bị lỗi
end

$a = 0	# => thay giá trị 0 cho biến global $a
foo	   # => gọi lệnh

[Kết quả hiển thị]

0

Cứ như vậy nếu chúng ta sử dụng biến global thù có thể chúng ta có thể tạo ra một biến số có thể dùng khắp mọi nơi.