Тип Dynamic

Необходимое пояснение: Переменные типа Dynamic часто бывают нужны для обеспечения взаимодействия со сторонними или платформенно-зависимыми библиотеками, или для очень специфичных случаев, где без динамически типизируемых переменных нельзя обойтись. В любом другом случае их использование не поощряется, так как их поведение разнится в зависимости от выбранной платформы.

Когда вам нужно получить динамически типизируемое поведение и освободиться от системы типов - используйте тип Dynamic, который можно подставить вместо любого типа без проверки во время компиляции:

    var x : Dynamic = "";
    x = true;
    x = 1.744;
    x = {};
    x.foo = 'bar';
    x = new Array();

Когда переменная помечена как "Dynamic", компилятор не проверяет типы для этой переменной. Это означает, что можно заменить один тип на другой. Также, любое присваивание, присваивание поля, или доступ по индексу сработает во время компиляции.

Однако во время выполнения, разные среды исполнения могут не распознать или даже не разрешить некоторые операции с конкретной переменной. К примеру, на flash9 (AVM2), когда динамической переменной присваивается конкретное значение (integer или скажем boolean), бросается исключение. На менее строгих платформах (как javascript) ошибки может и не возникнуть, но значение не сохранится.

var x:Dynamic = 4;
x.foo = "Bar";

//flash9:  
//ReferenceError: Error #1056: Cannot create property foo on Number.

//JavaScript: foo.x = null;

Если вы хотите создать объект, реализующий Dynamic, чтобы добавлять и удалять поля во время выполнения, следует действовать по другому. См. раздел 'Реализация Dynamic' ниже.

Попытка изменить поля экземпляра flash9 MovieClip сработает (т.к. он сам реализует тип Dynamic), но аналогичная попытка изменить поля flash9 Sprite вызовет ошибку времени выполнения:

// flash9
var m:Dynamic = new flash.display.MovieClip();
m.foo = "Bar";
trace(m.foo); // значение сохранено
var s:Dynamic = new flash.display.Sprite();
s.foo = "Bar"; // ReferenceError!

Суммируя сказанное выше, типы переменных "Dynamic" никогда не проверяются компилятором, ни в теле метода, ни в его аргументах. Но ограничения времени выполнения заданной цели остаются в силе и могут вызывать ошибки.

Переменная без указания типа будет иметь тип Unknown, а не Dynamic. Да, у переменной нет типа, пока он не будет определен выводом типа. Dynamic - наоборот, любой тип.

Параметры переменных типа Dynamic

Добавление параметра к типу Dynamic разрешает произвольный доступ и присваивание любому полю, если оно имеет тип параметра. Например, Dynamic<String> позволяет присваивать или читать поля, если в них содержится или создается строка. Это можно использоваться для создания Hash-таблиц с доступом с помощью точки (dot syntax):

    var att : Dynamic<String> = xml.attributes;
    att.name = "Николя";
    att.age = "26";
    // ...

or
    var foo : Dynamic<String> = cast {};
    foo.name = "Николя";

Реализация Dynamic

Любой класс так же может реализовывать "Dynamic" как с, так и без параметра типа. В первом случае поля класса будут типизированы когда он существует, во втором когда они имеют динамический тип.

class C implements Dynamic<Int> {
    public var name : String;
    public var address : String;
}
// ...
var c = new C();
var n : String = c.name; // ok
var a : String = c.address; // ok
var i : Int = c.phone; // ok : использовать Dynamic
var c : String = c.country; // ОШИБКА
// c.country это Int потому что из Dynamic<Int>

Динамическое поведение наследуется подклассами. Когда несколько классов реализуются разными "Dynamic"ескими типами в иерархии классов, то используется последний определённый как "Dynamic".

В случае доступа к неопределённому свойству на объект который реализует "Dynamic" будет вызвана функция "resolve". Эта функция вызывается с одним параметром, свойством к которому произошла попытка доступа, и может вернуть любое значение.

Приведение типов

Вы можете привести один тип к другому с помощью ключевого слова "cast".

     var a : A = ....
     var b : B = cast(a,B);

Это либо вернёт значение "a" с типом "B" если "a" является экземляром "B" либо возбудит исключение "Ошибка приведения класса" ('"Class cast error"''.)

Нетипизированные выражения и ключевое слово Untyped

Ещё один путь добиться динамического поведения это использовать ключевое слово "untyped". Когда выражение является "untyped" то проверка типа не производится и вы можете совершить много динамических операций над ним:

    untyped { a["hello"] = 0; }

Следите затем, что использование нетипизированных выражений действительно необходимо и вы точно знаете что делаете.

Небезопасное приведение

Ключевое слово "untyped" предоставляет существенную гибкость ценой возможного потенциально ошибочного синтаксиса справа от этого ключевого слова. Оно так же применимо к небезопасному приведению "cast" которое схоже со стандартным приведением за исключением того, что никакой тип не специфицируется. Это означает что вызов "cast" не приведёт к проверке во время выполнения, но позволяет вам "потерять" тип.

    var y : B = cast 0;

Небезопасное приведение похоже на сохранение значения во временной "Dynamic" перменной:

    var tmp : Dynamic = 0;
    var y : B = tmp;

«« Пакеты и импорт | Сложные типы данных »»

version #12224, modified 2012-01-16 23:06:31 by pinocchio964