User's collector

Внимание!   Данная опция будет доступна только после того, как вы авторизуетесь.
   запомнить меня 

Предлагаю нам продолжить разговор о тонкостях работы с классом Vector, начатый ранее в этой статье.

В ходе перевода некоторых классов разрабатываемого мною в том числе приложения на использование класса Vector, возник вопрос: «Каким образом можно наполнять экземпляр вектора нужными нам элементами при его создании?».

В случае использования массива это делается достаточно просто. Можно прибегнуть к конструктору массива:

Actionscript:
  1. var rows:Array = new Array(new Row(0, 25), new Row(183, 3));

либо же к литералу:

Actionscript:
  1. var rows:Array = [new Row(0, 25), new Row(183, 3)];

У конструктора класса Vector есть всего два строго фиксированных параметра: первый указывает длину создаваемого экземпляра, второй отвечает за то, возможно ли изменение длины вектора со временем. Поэтому передать нужные нам элементы в конструктор класса Vector у нас не получится. Литерала вектора не существует. Обратившись к документации по этому классу, максимум, что мы можем найти — это метод concat(...args):Vector.<T>, присоединяющий переданные аргументы к объекту. Т.е. следующий код:

Actionscript:
  1. var rows:Vector.<Row> = new Vector.<Row>();
  2. rows.push(new Row(0, 25));
  3. rows.push(new Row(183, 3));

может превратиться в:

Actionscript:
  1. var rows:Vector.<Row> = new Vector.<Row>().concat(new Row(0, 25), new Row(183, 3));

Однако если взглянуть на документацию более внимательно, то мы можем найти там глобальную функцию Vector, принимающую в качестве параметра исходный массив или вектор, элементы которого будут являться элементами будущего вектора, и возвращающую этот новый вектор. Синтаксис этой функции в точности повторяет синтаксис конструктора класса Vector, однако оператор new в этом случае использовать не нужно. И наш код превращается в следующий красивый и краткий кусок кода:

Actionscript:
  1. var rows:Vector.<Row> = Vector.<Row>([new Row(0, 25), new Row(183, 3)]);

Вот такие тонкости. Удачного вам программирования!

См. также:

9 комментариев

Теги:

С любезного разрешения Майка Чемберза (Mike Chambers), публикую перевод на русский язык его статьи «Using Vectors in ActionScript 3 and Flash Player 10». Дальнейшее повествование идет от имени Майка.

Одной из новых возможностей, появившихся в Flash Player 10 Public Beta, является включение в эту версию плеера нового класса Vector. По существу, класс Vector является массивом, но в дополнение к функционалу массива он отслеживает тип хранимых элементов данных, и поэтому может обеспечить (иногда довольно существенный) прирост производительности по сравнению с обычным массивом.

Пользоваться классом Vector так же просто, как и пользоваться классом Array. Фактически, класс Vector содержит все те же методы, что и класс Array, и главным отличием между ними является то, как вы создаете экземпляры этих классов.

Для примера, вот так вы инстанцируете экземпляр массива:

Actionscript:
  1. var a:Array = new Array();

ну или вот так:

Actionscript:
  1. var b:Array = [];

А это пример создания экземпляра вектора, который будет хранить объекты с типом int:

Actionscript:
  1. // var ИМЯ_ПЕРЕМЕННОЙ:Vector.<ТИП_ХРАНИМЫХ_ЭЛЕМЕНТОВ> = new Vector<ТИП_ХРАНИМЫХ_ЭЛЕМЕНТОВ>();
  2. var vector:Vector.<int> = new Vector.<int>();

Точно так же, как и в случае использования массива, вы можете инстанцировать экземпляры вектора конкретного размера, передавая длину в качестве первого необязательного параметра конструктора:

Actionscript:
  1. var size:int = 7;
  2. var vector:Vector.<int> = new Vector.<int>(size);

Кроме того, конструктор вектора имеет второй необязательный аргумент в виде булева флага, определяющего должен ли текущий экземпляр Vector быть фиксированного размера (true), либо же его длина в дальнейшем может изменяться (false). По умолчанию этот параметр имеет значение false. В дальнейшем его можно изменить обратившись к свойству fixed экземпляра класса Vector:

Actionscript:
  1. var size:int = 7;
  2. var fixed:Boolean = true
  3. var vector:Vector.<int> = new Vector.<int>(size, fixed);
  4. vector.fixed = !fixed;

Имейте в виду, что если свойство fixed установлено в true, то далее вы уже не можете вызывать методы изменяющие длину массива, например, методы pop(), push(), shift() и т.д.

Кроме того, Vector следит и за соблюдением единообразия типа хранимых в нем переменных, в то время как в массиве можно хранить элементы разных типов:

Actionscript:
  1. var s:String = "I am a string";
  2. var d:Date = new Date();
  3. var n:Number = 1138;
  4. var a:Array = new Array();
  5. a[0] = s;
  6. a[1] = d;
  7. a[2] = n;
  8.  
  9. trace(a[1] is Date); // true

Однако в этом случае у вас возникнут ошибки на этапе компиляции:

Actionscript:
  1. var s:String = "I am a string";
  2. var d:Date = new Date();
  3. var n:Number = 1138;
  4. var v:Vector.<String> = new Vector.<String>();
  5. v[0] = s;
  6. v[1] = d;
  7. v[2] = n;
  8.  
  9. trace(v[1] is Date); // false
  10.  
  11. // Ошибки этапа компиляции:
  12. // Implicit coercion of a value of type Date to an unrelated type String.       
  13. // Implicit coercion of a value of type Number to an unrelated type String.

Если не принимать во внимание эти различия, то работа с классом Vector очень похожа на работу с массивом. API обоих классов абсолютно идентичные. Кроме того, так же как и в случае использования массива, вы можете получить доступ к элементам Vector-а, обратившись к ним непосредственно по их индексу:

Actionscript:
  1. var vector:Vector.<int> = new Vector.<int>();
  2.  
  3. var rand:Number;
  4. for(var i:int = 0; i <1000000; i++)
  5. {
  6.         rand = (Math.floor(Math.random() * 1000000) as int);
  7.         vector.push(rand);
  8. }
  9. trace(vector[7]);

И последнее, что нужно иметь в виду при работе с векторами, заключается в том, что Vector представляет собой вариант «уплотненного» массива. Фактически, это означает, что все элементы, содержащиеся в экземпляре класса Vector должны иметь какое-либо значение или быть равными null. Например, при использовании массива вы можете свободно сделать следующее:

Actionscript:
  1. var a:Array = new Array();
  2. a[0] = "foo";
  3. a[6] = "bar";

Однако, если вы попробуете проделать то же самое с экземпляром Vector, то вы получите ошибку RangeError на этапе исполнения:

Actionscript:
  1. var v:Vector.<String> = new Vector.<String>();
  2. v[0] = "foo";
  3. v[6] = "bar";

Чтобы исправить это, зададим вектору длину при его создании:

Actionscript:
  1. var v:Vector.<String> = new Vector.<String>(7);
  2. v[0] = "foo";
  3. v[6] = "bar";

Ниже приведен пример, который показывает разницу в производительности при работе с вектором и массивом, каждый из которых содержит по миллиону чисел. Имейте в виду, что представленный ниже код — это только один специфичный тест, и повышение производительности в случае использования класса Vector в каждом конкретном приложении может быть как больше, так и меньше.

Actionscript:
  1. package
  2. {
  3.         import flash.display.Sprite;
  4.  
  5.         public class VectorTest extends Sprite
  6.         {
  7.                 private static const NUM_LOOPS:int = 5;
  8.                 public function VectorTest()
  9.                 {       
  10.  
  11.                         var vector:Vector.<int> = new Vector.<int>();
  12.                         var array:Array = new Array();
  13.  
  14.                         // Наполняем данными.
  15.                         var rand:Number;
  16.                         for(var i:int = 0; i <1000000; i++)
  17.                         {
  18.                                 rand = (Math.floor(Math.random() * 1000000) as int);
  19.                                 vector.push(rand);
  20.                                 array.push(rand);
  21.                         }
  22.  
  23.                         var sTime:Number = getMilliseconds();
  24.                         loopArray(array);
  25.                         trace("Loop Array Avg (5) : " + ((getMilliseconds() - sTime)/NUM_LOOPS));
  26.  
  27.                         sTime = getMilliseconds();
  28.                         loopVector(vector);
  29.                         trace("Loop Vector Avg (5) : " + ((getMilliseconds() - sTime)/NUM_LOOPS));
  30.  
  31.                 }
  32.  
  33.                 private function getMilliseconds():Number
  34.                 {
  35.                         return (new Date()).getTime();
  36.                 }
  37.  
  38.                 private function loopArray(a:Array):void
  39.                 {
  40.                         var len:Number = a.length;
  41.  
  42.                         var n:int;
  43.                         for(var i:int = 0; i <NUM_LOOPS; i++)
  44.                         {
  45.                                 for(var k:int = 0; k <len; k++)
  46.                                 {
  47.                                         n = a[k];
  48.                                 }
  49.                         }
  50.                 }
  51.  
  52.                 private function loopVector(v:Vector.<int>):void
  53.                 {
  54.                         var len:Number = v.length;
  55.  
  56.                         var n:int;
  57.                         for(var i:int = 0; i <NUM_LOOPS; i++)
  58.                         {
  59.                                 for(var k:int = 0; k <len; k++)
  60.                                 {
  61.                                         n = v[k];
  62.                                 }
  63.                         }
  64.                 }
  65.         }
  66.  
  67. }

На моей машине вывелись следующие значения:

CODE:
  1. Loop Array Avg (5) : 115.8
  2. Loop Vector Avg (5) : 108.8

Что является довольно значительной разницей, с учетом простоты теста (выборка значения элемента по индексу).

Вы можете найти больше информации о классе Vector, обратившись к документации по Flash Player 10 Beta, а так же к информации о Flash Player 10 на Adobe Labs.

См. также:

4 комментария

Теги: