# BOO大全/函式

### 函式

Boo 的函式以 def 關鍵字定義，而回傳值則以 return 表示傳回。

```def sqr(x as double):
return x*x
```

```double sqr(double x) {
return x*x;
}
```

```>>> res
(20, 2.4)
>>> def Fun(x as (double)):
... 	x[0] = 1.0
...
>>> Fun(res)
>>> res
(1, 2.4)
```

```def yes():
print "yes was entered"

def no():
print "no was entered"

line = prompt("enter yes or no:")
if line == "yes":
fn = yes
else:
fn = no
fn()
```

#### 遞迴函式

Boo 的遞迴函式比較特別的是，他們通常需要明確地指定回傳型別，因為這很難由型別推導中得到。下面是一個很經典的階乘遞迴函式：

```def fact(n as int) as int:
if n < 2:
return 1
else:
return n*fact(n-1)
```

fact 並不是個很有用或很有效率的函式，但它卻很適合用來表達我想說的。

```import System.IO
def FilesInFolder(path as string, mask as string) as List:
files = [file for file in Directory.GetFiles(path,mask)]
for dir in Directory.GetDirectories(path):
return files

res = FilesInFolder(Directory.GetCurrentDirectory(),"*.boo")
print join(res,'\n')
```

```def Reverse(ls as List) as List:
if len(ls) < 2:
return ls[:]
else:
return Reverse(ls[1:])+ls[0:1]
```

#### Boo並不是Python

Boo 使用 Python 的語法，同時加入許多很酷的 Python 特性，像字串與陣列的slicing、串列...等等。但是它是個非常不同的語言，就像 Java 明顯地是以C++語法為基礎但卻不是 C++ 一樣。所以語法本身並不重要，它只是語言的表面。Python 是個動態型別的語言，Boo 則全然是個靜態型別的語言 (但是，請參考 DuckTyping，只是在很多地方使用了型別推導來避免明確地指定型別。

#### 函式多載

```def Square(n as int):
return n*n

def Square(x as double):
return x*x

assert Square(10).GetType() == int
assert Square(2.3).GetType() == double
```

```def DrawBox(pos as Point, size as Size, colour as Color):
....

def DrawBox(pos as Point, size as Size):
DrawBox(pos,size,Color.Black)

def DrawBox(pos as Point):
DrawBox(pos,Size(1,1),Color.Black)
```
```與這很接近的，Boo 可以讓你在建構物件時就指定公開屬性的值，例如：btn = Button(Text : "Hello", Location : Position(100,100))
```

```>>> def f(x as single):
... 	return x
...
>>> def f(i as int):
... 	return i
...
>>> f(2.3)
-----^
ERROR: Ambiguous reference 'f': Input43Module.f(System.Single), Input44Module.f(System.Int32).
```

#### 傳遞多個值

```>>> def Max(*x as (double)):
... 	ret = double.MinValue
... 	for val in x:
... 		ret = System.Math.Max(ret,val)
... 	return ret
...
>>> Max(2.4,2,4,5,4)
5
>>> arr = (1.0,5,6,4,2)
>>> Max(*arr)
6
```

```import System
def PrintNumbers(s as string, *numbers as (double)):
Console.Write("{0}: ",s)
for x in numbers:
Console.Write("{0} ",x)
Console.WriteLine()

PrintNumbers("Some numbers",2,3,6,2,1)
```

#### 回傳多個值

```def Modifies(ref a as int, ref x as double):
a = 20
x = 2.4

k = 1
z = 1.2
Modifies(k,z)
print k,z
```

```20 2.4
```

```>>> def ReturnsTwo():
... 	return (20,2.4)
...
>>> res = ReturnsTwo()
>>> res
(20, 2.4)
>>> x1,x2 = ReturnsTwo()
>>> print x1,x2
20 2.4
```

```>>> def ReturnsAMixedBag():
... 	return ("a string",20,2.4)
...
>>> s,i1,x1 = ReturnsAMixedBag()
```

#### 匿名函式

• 你不用取名字
• closures 包含當前的狀態

```line = prompt("enter yes or no:")
if line == "yes":
fn = def():
print "yes was entered"
else:
fn = def():
print "no was entered"

fn()
```

closures 跟一般函數一樣也可以有引數：

```if argv[0] == "sqr":
fn = def(x as double):
return x*x
elif argv[0] == "cube":
fn = def(x as double):
return x*x*x
```

```getline = def():
while line = getline():
print line
```

```getline = { System.Console.In.ReadLine() }
while line = getline():
print line
```

map 內建函式可以將序列裡的每個元素傳入指定的函式來進行處理。下面就是將序列裡每個元素都作平方的例子：

```def sqr(x as double):
return x*x

iter = map(range(0,10),sqr)
print join(iter)
```

```iter = map(range(0,10)) def(x as double):
return x*x
for n in iter:
print n
```

```iter = map(range(0,10),{x as double | x*x})
for n in iter:
print n
```

closure 可以存取範圍外的任何變數。

```list = [1,2,3,4,5]
sum = 0.0
l2 = map(list) def(i as int):
sum += i
return sum
print join(l2)
```

```1 3 6 10 15
```

#### callable型別

```callable DoubleFun(x as double) as double

def Dump(fn as DoubleFun):
for i in range(0,10):
print i,fn(i)

Dump(System.Math.Sin)
```

```def isqr(i as int):
return i*i

Dump(isqr)
```

```def dbl(s as string):
return s+s
Dump(dbl)
*** Dump(DoubleFun) is not compatible with the argument list
*** '(callable(System.String) as System.String)'
```

```btn.Click += def(o as object, e as EventArgs):
print "I was clicked"
```

```btn.Click += def():
print "That's better!"
```

#### ICallable介面

```class Fred(ICallable):
def Call(args as (object)) as object:
return (args[0] as string) + (args[1] as string)

f = Fred()
assert f('one','two') == 'onetwo'
```