Abstract是一种运行时类型。定义它可以修改或增强其行为:
abstract AbstractInt(Int) {
inline public function new(i:Int) {
this = i;
}
}
class Main {
static public function main() {
var a = new AbstractInt(12);
trace(a); //12
}
}
//------------------以上代码在编译成js的时候,如下所示
var a = 12;
console.log(a);
与类不同,Abstract允许定义隐式类型转换。有两种隐式类型转换:
1、直接转化:允许将抽象类型直接强制转换为其他类型或从其他类型直接强制转换。如下例子:
abstract MyAbstract(Int) from Int to Int {
inline function new(i:Int) {
this = i;
}
}
class Main {
static public function main() {
var a:MyAbstract = 12;
var b:Int = a;
}
}
2、类字段通过元方法转化。例子如下:
abstract MyAbstract(Int) {
inline function new(i:Int) {
this = i;
}
@:from
static public function fromString(s:String) {
return new MyAbstract(Std.parseInt(s)); 、
}
@:to
public function toArray() {
return [this];
}
}
class Main {
static public function main() {
var a:MyAbstract = "3";//from元方法(metadata,翻译成元数据,我更喜欢叫元方法)启动
var b:Array<Int> = a; //to 元方法启动
trace(b); // [3]
}
}
下一个例子加深一下印象:
abstract A(Int) {
public function new() this = 0;
@:to public function toB() return new B();
}
abstract B(Int) {
public function new() this = 0;
@:to public function toC() return new C();
}
abstract C(Int) {
public function new() this = 0;
}
class Main {
static public function main() {
var a = new A();
var b:B = a; // valid, uses A.toB
var c:C = b; // valid, uses B.toC
var c:C = a; // error, A should be C
}
}
这种无语的例子,没啥好说的。
重头戏开始了:运算符的重载,C++中有这块,有元方法的语言都有这块,通过元方法重载运算符,可以最大限度的加强自定义抽象类型的功能。这块怎么说,笨办法呢手写一些函数实现,但是聪明的人总想点办法用这个偷点懒,把麻烦解决在开始阶段,想想也是好的。
abstract MyAbstract(String) {
public inline function new(s:String) {
this = s;
}
@:op(A * B) //这种是典型的元数据操作,不懂的需要恶补MetaData
public function repeat(rhs:Int):MyAbstract {
var s:StringBuf = new StringBuf();
for (i in 0...rhs)
s.add(this);
return new MyAbstract(s.toString());
}
}
class Main {
static public function main() {
var a = new MyAbstract("foo");
trace(a * 3); // foofoofoo
}
}
再来个例子
abstract MyAbstract(String) {
public inline function new(s:String) {
this = s;
}
@:op(++A) public function pre()
return "pre" + this;
@:op(A++) public function post()
return this + "post";
}
class Main {
static public function main() {
var a = new MyAbstract("foo");
trace(++a); // prefoo
trace(a++); // foopost
}
}
下一个坑:公开内含类型操作
比方Int类型吧,总是允许比较大小,对吧? var a:Int=3;var b:Int=2; 对于Int ,就有一个比较操作,现在我们定义Abstract(int)的时候。我们就可以操作gt(大于)的这种方法了,实现增强操作。但是不能把这个用于Abstract(Bool) 上,因为Bool没有比较大小的操作符。来个例子:
abstract MyAbstractInt(Int) from Int to Int { //直接定义法
// The following line exposes the (A > B) operation from the underlying Int
// type. Note that no function body is used:
@:op(A > B) static function gt( a:MyAbstractInt, b:MyAbstractInt ) : Bool;
}
class Main {
static function main() {
var a:MyAbstractInt = 42;
if(a > 0) trace('Works fine, > operation implemented!');
// The < operator is not implemented.
// This will cause an 'Cannot compare MyAbstractInt and Int' error:
if(a < 100) { }
}
}