BOO大全/型别转换
型别转换
编辑某些型别可以隐性地转换为其他型别,所以明确的转换是丑陋且不必要的。任何数值型别可以转换为其他数值型别。如果类别实作了某个介面,那么以此类别产生的物件可以自动转换为该介面型别﹔同样的,衍生类别也是。你最好的指引就是(总是)编译器本身。
但要当心,有些转换编译器会允许,可是却只能在执行时期决定是否可行。
def one(o as object):
print 'one',o
def two(s as string):
print 'two',s
def three(n as int):
print 'three',n
one("hello")
one(42)
two("dolly")
# two(66) <= compile-time error - string doesn't cast to int.
# best overload for the method 'implicitCast1Module.two(System.String)'
# is not compatible with the argument list '(System.Int32)'
obj as object
obj = "hello dolly"
two(obj)
obj = 42
three(obj)
obj = 'hello'
three(obj) <= ok with compiler, but causes an InvalidCastException at run-time.
虽然 three 函式的引数型别为 int,但编译器会允许让型别为 object 的物件传入,这是因为只有在执行时,才会知道这个物件真正的型别为何。(你可能不认同这点,认为编译器应该要检查﹔不过事实就是如此,请记住这点,并把它当作一个特例。)
这些静态编译器的错误顺便也让你看到几项Boo的特色。第一点, int 是 System.Int32 的别名。第二点,单独的函式其实是模组类别(被自动产生)里的静态方法。第三点,函式可以多载,这是为什么编译器并非简单地告诉你引数不相符的原因。
字串是一个参考物件,所以 null 对字串变数来说,是个很好的合法值,这也表示字串是个可为null的型别。对照简单的值型别,像整数,它无法有个特别的值用来表示"非整数"。 0 不是一个好的候选者,因为很多有意义的整数也是 0。
在 Boo 有两种明确进行转换型别的方法,第一种方法适用于所有型别,但如果无法转换时,会提出编译或执行时期错误。举例来说,一个为 object 型别的变数可能是任何型别,所以如果这个 object 变数里不包含要求的型别时,将会提出InvalidCastException例外。
>>> s = "Hello, World!" >>> n = 10 >>> cast(double,n) (Double) 10 >>> cast(string,n) ----^ ERROR: Cannot convert 'System.Int32' to 'System.String'. >>> obj as object # declare as object (initial value null) >>> obj = "Hello, World!" >>> cast(int,obj) System.InvalidCastException: Specified cast is not valid. ....
作者:Booish 真的是个不可思议的工具,我建议你一定要使用他来学习 Boo。但有个地方可能会与编译时的行为不同,你要特别注意,那就是 Booish 预设会将 DuckTyping 选项打开。
第二种方法是使用 as 关键字作为运算子。下面的范例除了示范变数宣告以外,也示范了型别转换。
s as object = "hello dolly" ss = s as string print ss.ToUpper()
在上面的例子你也可以使用 cast,但 as 在错误时不会提出例外,只会回传 null。也因此,as 不能搭配像数值等的值型别来使用。这儿有两个例子,说明了这件事情,同样都可以用来检查 k 是否为整数:
k as object = 42 if (ss = k as string) != null: print ss.ToUpper() else: print "was not a string!" if k isa string: ss = (k as string).ToUpper() print ss else: print "was still not a string!"
在执行时期侦测型别时,isa 运算子非常有用﹔个人认为第二种方法会比较好。