iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 16
0
Software Development

30天 Lua重拾筆記系列 第 16

【30天Lua重拾筆記16】基礎2: 多值返回&具名參數

本文同步發表於個人網站

回傳多值/多值返回

Lua函數可以返回多值。在我看來,這個特性是特殊的,只有少數語言真正做到多值返回。什麼意思?這表示在接收一個函數的返回值,可以輕易忽略掉主要值以外的結果。這些結果一般用於輔助,絕大多數時候,我們不關心、不需要,但有時候非常有作用。

先來看看Python裡的dict.get

_d = {}
_v = _d.get("key", "value")

print(_v) # => Output: value

大多數時候,並不關心_v的值是否真的從_d來的,還是其實是個預設值。如果我們想要確定,那就要在多寫一次:

found = "key" in _d

我們可以替Lua寫一個相似的函數,但其還多返回一個用於解釋是否是有找到的值:

function get(dict, key, default)
  if dict[key] ~= nil then
    return dict[key], true
  else
    return default, false
  end
end

其實可以在簡化一些:

function get(dict, key, default)
  return (dict[key] or default), dict[key] ~= nil
end

這麼一來,平常可以這樣用:

_d = {}
_v = get(_d, "key", "value")
print(_v) -- => Output: value

如果還需要而外知道是否是從_d找到的, 可以這樣寫:

_d = {}
_v, found = get(_d, "key", "value")
print(_v) -- => Output: value
print(found) -- => Output: false

這樣就很像Common Lisp裡面,gethash的行為:

(defvar *h* (make-hash-table :test 'equal))
(multiple-value-bind
      (_v found) (gethash 'key *h* "value")
  (print _v)  ;; => Output: value
  (print found)) ;; => Output: Nil

Python

與Python相比,Python的多值返回比較像是ES6的解構賦值。實際上他是返回一個Tuple

def get(_d:dict, key, default):
    return _d.get(key, default), key in _d

_d = {}
_v, found = get(_d, "key", "value")
print(_v, found) # => value True

_v = get(_d, "key", "value")
print(_v) # => ('value', False)

第二次的_v,並不如預期只接受主要返回值"value",而是整個返回值("value", False)

Golang

依我理解,Go語言中也有多值返回。不過如果不使用返回值,必須顯式忽略:

package main

import (
	"fmt"
)

func main() {
	v, _ := get()
	fmt.Println(v)
}

func get() (int, bool) {
	return 1, true
}

當中get的第二個返回值如果不使用,必須使用佔位_來明確示不使用。

少數的例外可能只有內建的Map取值,這與上例的行為一致:

package main

import (
	"fmt"
)

func main() {
	m := make(map[string]int)	
	v := m["key"]
	fmt.Println(v)  // Output: 0
}

map會返回預設的零值,整數的零值就是0。此外其實還會返回一個是否查找到的值:

package main

import (
	"fmt"
)

func main() {
	m := make(map[string]int)	
	v, ok := m["key"]
	fmt.Println(v, ok)  // Output: 0 false
	
	m["key"] = 50
	
	v, ok = m["key"]
	fmt.Println(v, ok) // Output: 50 true
}

相關可以參考官方文件

具名參數

函數一章,已經說過不定長參數,也提到過函數呼叫的語法糖。Lua沒有具名參數,不能像Python那樣明確指定參數名稱。不過透過語法糖仍然可以做到類似的功能。

function Person(info)
  local person = {}
  person.name = info.name or "Bob"
  person.age = info.age or 20
  person.address = info.address or ""
  return person
end

p1 = Person {
  name = "Tina",
  age = 13,
  address = "secret"
}

print("Name:    ", p1.name)
print("Age:     ", p1.age)
print("Address: ", p1.address)

Name: Tina
Age: 13
Address: secret

位置參數

這樣語法糖的寫法,還可以混合著位置參數:

function Person(args)
  local person = args
  person.name = args.name or "Bob"
  person.age = args.age or 20
  person.address = args.address or ""
  return person
end

p1 = Person {
  "位置參數1",
  age = 13,
  address = "secret",
  "位置參數2",
}

print("Name:    ", p1.name)
print("Age:     ", p1.age)
print("Address: ", p1.address)
print("-------------")
print("位置參數:", p1[1], p1[2])

Name: Bob
Age: 13
Address: secret

位置參數: 位置參數1 位置參數2


上一篇
【30天Lua重拾筆記15】基礎2: Label and Goto
下一篇
【30天Lua重拾筆記17】基礎2: pcall, xpcall, load (eval, exec, apply)
系列文
30天 Lua重拾筆記36

尚未有邦友留言

立即登入留言