BOO入门/函数

维基教科书,自由的教学读本

BOO入门 > 函数 (上一章:运算子 下一章:类别)


定义 定义 函数:用来执行特定任务的程式码,包含了一个或多个程式区块。

内建函数[编辑]

前面几个章节已经提过也使用过了部分函数:range()、print() 和 join()。这些都是 Boo 所内建的函数,这里列出所有 Boo 提供的内建函数:

名称 描述 范例
print 将物件输出到标准输出。这与 System.Console.WriteLine 相同。 print("hey")
gets 从标准输入取得字串,与 System.Console.ReadLine() 相同。 input = gets()
prompt 询问使用者特定问题并从标准输入取得字串。 input = prompt("How are you? ")
join 遍访 IEnumerable 物件并将所有元素放到一个字串里。
join([1, 2, 3, 4, 5]) == "1 2 3 4 5"
map 对 IEnumerable 物件里的全部元素执行同一函数,然后将结果放到一个新的 IEnumerable 物件之后回传。
for i in map([1, 2, 3, 4, 5], { x | return x*x } ): print i
(译注,例子与原文不同,这里使用 closure (类似 C# 的 anonymous method),并加上循环印出结果。 )
array 用来建立一个空阵列或是将 IEnumerable 和 ICollection 物件转换为阵列。 array(int, [1, 2, 3, 4, 5]) == (1, 2, 3, 4, 5)
matrix 建立多维阵列。请参考 Multidimensional Arrays 。(译注:原文找不到此节。) matrix(int, 2, 2)
iterator 从物件取得一个 IEnumerable List(iterator('abcde')) == ['a', 'b', 'c', 'd', 'e']
shellp 启始一个程序,并回传 Process 物件。 process = shellp("MyProgram.exe", "")
shell 执行应用程序,并将应用程序输出到标准输出的结果放到字串里面回传。 input = shell("MyProgram.exe", "") // 译注:原文为 "echo hi there" ,经测试,不管是在 Windows 或 Linux 都无法执行
shellm 在新的 AppDomain 里执行特定 managed 应用程序,同样,会把应用程序输出到标准输出的结果放到字串里面回传。 input = shellm("MyProgram.exe", (,))
enumerate 从 IEnumerator 物件建立新的 IEnumerator,但是会变成类似 (index, value) 的形式。 array( enumerate( range(5,8) ) ) == ((0, 5), (1, 6), (2, 7)) (译注:原文用 List,这里改用 array,因为用 List 会传回 object,不容易看出结果。)
range 回传包含整数串列的 IEnumerable 物件。 List(range(5)) == [0, 1, 2, 3, 4]
reversed 回传 IEnumerable,但里面成员的顺序会变成相反。 List(reverse(range(5))) == [4, 3, 2, 1, 0]
zip 会回传一个经过混搭多个 IEnumerables 物件的 IEnumerable 物件。 array(zip([1, 2, 3], [4, 5, 6])) == ((1, 4), (2, 5), (3, 6)) (译注:原文为 List([1,2,3],[4,5,6]),应为 zip 才对,此处已修正) 或看这个例子:array(zip(['a','b','c'],[4,5,6],['aa','bb','cc']))==(('a', 4, 'aa'), ('b', 5, 'bb'), ('c', 6, 'cc'))
cat 串接多个 IEnumerable 物件。 List(cat(range(3), range(3, 6)) == [0, 1, 2, 3, 4, 5]

这些函数你都应该要知道,因为他们非常有用,能让写程式变得更简单。

定义自己的函数[编辑]

定义自己的函数非常简单:

// 宣告函數
def Hello():
    return "Hello, World!"

print Hello()

输出结果

Hello, World!

如果你不懂的话,下面会一步步地解说:

  1. def Hello():
    • def 表示你要开始宣告一个函数,def 表示 define。
    • Hello 是函数的名称。你可以取任何你想要的名字,但这名字里不能有空白,也不能以数字开头。
    • () 表示函数要使用的引数。这里不使用任何引数,所以里面是空的。
  2. return "Hello, World!"
    • return 是个关键字,这让函数知道该回传些什么给呼叫这个函数的地方。
    • "Hello, World!" 是个字串,也就是 return 要回传的东西。
  3. print Hello()
    • print ,我们之前提过了,就是印出变数的内容。
    • Hello() 呼叫 Hello 函数,并且不带引数。

如同变数一样,函数回传值的型别也会被自动推断并决定。所以,

def Hello():
    return "Hello, World!"

Hello() 将永远回传字串,所以 Boo 将会推断字串是他的回传型别。也就是跟下面的程式码一样:

def Hello() as string:
    return "Hello, World!"
建议 建议 如果程式的语意不够清楚的话,帮函数加上回传型别的宣告。

如果 Boo 无法推断回传型别,它会假设为 object。如果没有回传值,那么回传型别会是 void,void 表示不回传值。要定义一个无回传值的函数,就不要在函数里面使用 return,或就写 return 就好。如果函数里面有好几个 return,而回传值的型别又不同的时候,回传型别将会是最接近的原型,通常是 object,但并非绝对。

译注:"回传型别将会是最接近的原型"的意思是,如果回传的值刚好都继承同一个父类别时,回传型别将会被推断为它们的父类别。但因为 .Net 里面所有型别都兼容于 object,所以才说,"通常是 object"。另外,说兼容的原因是,像 int、bool, decimal 等等其实都是 struct,并不继承 object。

引数[编辑]

定义 定义 引数:允许相同顺序的命令去操作不同的资料,而无须重新指定指令。

引数非常有用,这允许函数可以依据输入来做出不同的事情。

// 引數範例
def Hello(name as string):
    return "Hello, ${name}!"

print Hello("Monkey")

输出结果

Hello, Monkey!

这里同样提供步骤的说明:

  1. def Hello(name as string):
    • def 表示开始宣告函数。
    • Hello 是函数的名称。你可以用任何你可以想到的名字,但是不能有空白,也不能以数字开头。
    • (name as string) 这表示函数要使用的引数。这个函数将会使用一个引数:name。当呼叫此函数时,name 必须是个字串,否则你会得到一个编译错误 - "The best overload for the method Hello is not compatible with the argument list '(The,Types, of, The, Parameters, Entered)'."
  2. return "Hello, ${name}!"
    • return 是个关键字,表示离开函数,并且可以传回一个值给呼叫者(当然也可以不传回值)。
    • "Hello, ${name}!" 使用了字串插值将 name 的值直接放到字串里面去。
  3. print Hello("Monkey")
    • print 正如之前提到的,就是将物件印出的 macro。
    • Hello("Monkey") 将 ("Monkey") 当作引数传入并呼叫 Hello 函数。

函数的多载[编辑]

定义 定义 Overloading:同样的名称却有不同的含意,这在语意上可以区别出来。举例来说,有同样名称的两个函数,编译器可以根据函数引数的个数、型别或是回传的型别来区别出你所要呼要的函数为何。

当函数被以不同引数宣告了数次时,函数多载就发生了。

// overloading example
def Hello():
    return "Hello, World!"

def Hello(name as string):
    return "Hello, ${name}!"

def Hello(num as int):
    return "Hello, Number ${num}!"

def Hello(name as string, other as string):
    return "Hello, ${name} and ${other}!"

print Hello()
print Hello("Monkey")
print Hello(2)
print Hello("Cat", "Dog")

输出结果

Hello, World!
Hello, Monkey!
Hello, Number 2!
Hello, Cat and Dog!

不定个数的引数[编辑]

要传递不定数目的引数时,可以这么作:

// 不定引數的範例
def Test(*args as (object)):
    return args.Length

print Test("hey", "there")
print Test(1, 2, 3, 4, 5)
print Test("test")

a = (5, 8, 1)
print Test(*a)

输出结果

2
5
1
3

在函数对引数的宣告加上 * 是让函数知道引数的数目将不固定,如果要直接把容器变数当作引数传递时,得在呼叫函数时加上 *,以表示要把指定容器变数里的元素当作引数传递到函数里面去。以上面的例子来说,也就是把 a 里面的三个元素当作引数传递到函数里面去。 如果有一定需要(也就是必要)的引数的话,请宣告在不定引数的前面,可千万别放到不定引数后面去了。

练习[编辑]

  1. 写个函数,让它能在传入值为偶数时,印些好的字眼﹔在传入值为奇数时,印些不好的字眼。