这次美国之行的一大收获就是终于正视了Objective-C而不再只是当它是不顺手的工具了。这主要是有机会拜读了Brad Cox的《Objective-Oriented Programming, an evolutionary approach》。今天就谈谈它第91页提到的那个极少C程序员甚至C编译器作者知道的一个极为馄饨的语法:
- struct MYSTRUCT someVariables;
- someVariable = (*((struct MYSTRUCT *)(*)() _msg))(someObject, …);
C语言是静态类型检查的编译语言.例如下面程序定义和使用了两个类型:浮点和定点。
- #include <stdio.h>
- typedef struct {
- float x, y;
- } FloatingPoint;
- typedef struct {
- int x, y;
- int scale;
- } FixedPoint;
- int main() {
- FloatingPoint flo;
- FixedPoint fix;
- printf("(%f,%f)\n", flo.x, flo.y);
- printf("(%f, %f)\n", 1.0*fix.x/fix.scale, 1.0*fix.y/fix.scale);
- }
不同类型间的转换需要cast,否则编译时会被警告。后门还是有的,就是void *类型。我们声明id是此void *类型,加入一个使用它的迷你函数:
- typedef void *id;
- id thePoint(id thePoint) {
- return thePoint;
- }
这样在main里我们可以使用明确的类型转换,不会被警告:
- id flid = thePoint(&flo);
- printf("(%f,%f)\n", ((FloatingPoint *)flid)->x, ((FloatingPoint *)flid)->y);
但类型错了也没了警示报告:
- FloatingPoint *flip = thePoint(&fix);
- printf("(%f,%f)\n", flip->x, flip->y);
我们试着改写为间接的函数指针类型,当然也没有编译预警:
- id (*thePointPointer)(id);
- thePointPointer = &thePoint;
- flip = thePointPointer(&fix);
- printf("(%f,%f)\n", flip->x, flip->y);
但如果我们加入明确类型,就会看到预期的警示,虽然是有些啰嗦:
- FloatingPoint *(*theFloatingPointPointer)(FloatingPoint *);
- theFloatingPointPointer = &thePoint;
- flip = theFloatingPointPointer(&fix);
- printf("(%f,%f)\n", flip->x, flip->y);
但这很容易解决,写在一行就行了:
- FloatingPoint *flop = ((FloatingPoint *(*)(FloatingPoint *))&thePoint)(&fix);
我想这就是书中提到的意思。Objective-C是超级的C语言,这些馄饨都被精心的包装成了简洁的语法。带类型检查的动态语言 —— 我喜欢。