Какой тип для индексного свойства
Индексные свойства
Индексные свойства ведут себя аналогично полям-массивам и используются, как правило, для доступа к элементам контейнеров. Как и при использовании обычных свойств, при использовании индексных свойств могут попутно выполняться некоторые действия.
Индексное свойство описывается в классе следующим образом:
property Prop[описание индексов]: тип read имя функции чтения write имя процедуры записи;
В простейшем случае одного индекса описание индексного свойства выглядит так:
property Prop[ind: тип индекса]: тип read имя функции чтения write имя процедуры записи;
В этом случае функция чтения и процедура записи должны быть методами этого класса и иметь следующий вид:
function GetProp(ind: тип индекса): тип;
procedure SetProp(ind: тип индекса; v: тип);
Всякий раз, когда мы для объекта a, содержащего свойство Prop, выполняем присваивание a.Prop[ind] := value, вызывается процедура SetProp(ind,value), а когда считываем значение a.Prop[ind], вызывается функция GetProp(ind).
Индексное свойство, после которого добавлено ключевое слово default с последующей ;, называется индексным свойством по умолчанию и позволяет пользоваться объектами класса как массивами, т.е. использовать запись a[ind] вместо a.Prop[ind].
Принципиальное отличие индексных свойств от полей-массивов состоит в том, что тип индекса может быть произвольным (в частности, строковым). Это позволяет легко реализовать так называемые ассоциативные массивы, элементы которых индексируются строками.
В следующем примере индексное свойство используется для закрашивания/стирания клеток шахматной доски в графическом режиме.
uses GraphABC;
const
n = 8;
sz = 50;
type ChessBoard = class
private
a: array [1..n,1..n] of boolean;
procedure setCell(x,y: integer; value: boolean);
begin
if value then
Brush.Color := clWhite
else Brush.Color := clBlack;
Fillrect((x-1)*sz+1,(y-1)*sz+1,x*sz,y*sz);
a[x,y] := value;
end;
function getCell(x,y: integer): boolean;
begin
Result := a[x,y];
end;
public
property Cells[x,y: integer]: boolean read getCell write setCell; default;
end;
var c: ChessBoard := new ChessBoard;
begin
var x,y: integer;
for x:=1 to n do
for y:=1 to n do
c[x,y] := Odd(x+y);
end.
Следующая глава >
Похожие главы из других книг:
Свойства
Прежде всего надо отметить, что объект document существует в единственном экземпляре для всего HTML-документа. Он присутствует всегда, если существует HTML-документ, поэтому специально создавать его не требуется.activeElementИспользуется в сценарии для получения ссылки на
Свойства
Объект window представляет текущее окно Web-обозревателя или отдельный фрейм, если окно разделено на фреймы.closedВозвращает true, если текущее окно закрыто. Может быть использовано при работе с несколькими окнами.defaultStatusСообщение по умолчанию, отображаемое в строке
Свойства
aboveВозвращает ссылку на слой, находящийся над текущим (т.е. выше в z-последовательности). Если таких нет, возвращается null.backgroundСсылка но объект Image, представляющий фоновый ресунок текущего слоя. Вы можете использовать свойство src этого объекта для задания или
Индексные дескрипторы
Индексный дескриптор, или inode, содержит информацию о файле, необходимую для обработки данных, т.е. метаданные файла. Каждый файл ассоциирован с одним inode, хотя может иметь несколько имен в файловой системе, каждое из которых указывает на один и тот же
Виртуальные индексные дескрипторы
Дисковый файл обычно имеет связанную с структуру данных, называемую метаданными или inode, где хранятся основные характеристики данного файла и с помощью которой обеспечивается доступ к его данным. Одним из исключений из этого правила
2.5 Индексные дескрипторы
Файл имеет несколько атрибутов: имя, содержимое и служебную информацию (права доступа и даты модификации). Служебная информация размещается в индексном дескрипторе вместе с важной системной информацией, такой, как размер файла, место хранения
16.3. Индексные дескрипторы файлов
Каждому файлу на диске соответствует один и только один индексный дескриптор файла, который идентифицируется своим порядковым номером — индексом файла. Это означает, что число файлов, которые могут быть созданы в файловой системе,
Свойства WMI
Для работы оснастки Управляющий элемент WMI необходимо, чтобы в системе был зарегистрирован GUID-номер {5C659257-E236-11D2-8899-00104B2AFB46}. Именно этот GUID-номер и идентифицирует настройки оснастки Управляющий элемент WMI. Эта оснастка входит в состав консоли Инфраструктура
1.1.6. Свойства
TUUCode компонент имеет восемь опубликованных свойств (мы здесь опустим описание обработчиков событий):Свойство About содержит информацию о правах и версии.Свойство Active может использоваться для вызова преобразования UUCode во время разработки (design time), подобно
Свойства документа
Работая с документами Word, часто необходимо сохранить их свойства, то есть указать, что представляет собой данный документ, кто занимается его созданием и редактированием, вынести ключевые слова и заметки. Это особенно актуально для документов, которые
Свойства таблицы
В Microsoft Word 2007 есть очень удобный набор функций, объединенных в окне Свойства таблицы (рис. 5.21). Его можно открыть, щелкнув правой кнопкой мыши в любом месте таблицы и выполнив команду Свойства таблицы или нажав кнопку Свойства в группе Таблица на вкладке
Свойства, доступные только для чтения, и свойства, доступные только для записи
При создании типов класса можно создавать свойства, доступные только для чтения. Для этого просто создайте свойство без соответствующего блока set. Точно так же, если вы хотите иметь свойство,
Индексные выражения
Синтаксис:<выражение1>[<выражение2>]Здесь квадратные скобки являются символами языка Си, а не элементами описания.Значение индексного выражения находится по адресу, который вычисляется как сумма значений <выражения1> и <выражения2>.
Свойства записи
В программе Sound Forge все действия, связанные с записью, выполняются в окне Record (Запись) (рис. 7.5), для открытия которого необходимо выполнить команду Special ? Transport ? Record (Дополнительно ? Перемещение ? Запись).
Рис. 7.5. Окно Record (Запись)О записи поговорим позже, а
Статический анализ кода стремится взять под контроль все конструкции кода, чтобы повысить типобезопасность программы и тем самым переложить работу, связанную с выявлением ошибок, на себя, оставляя разработчикам больше времени на более важные аспекты. И несмотря на то, что динамические операции являются причиной “головной боли” компилятора, потребность в них при разработке программ все-таки существует. Одной из таких операций является создание в объектном типе данных индексных членов (динамических ключей).
Индексная сигнатура (index signature) состоит из двух частей. В первой части расположен имеющий собственную аннотацию типа идентификатор привязки (binding identifier), заключенный в квадратные скобки. Во второй части расположена аннотации типа (type annotation).
При объявлении индексной сигнатуры не должны быть использованы модификаторы доступа и модификатор static, а идентификатор привязки должен принадлежать либо к типу string, либо к типу number. В качестве типа, указанного справа от двоеточия, может быть указан любой тип данных. Идентификатора привязки может иметь произвольное имя.
[identifier: string]: string
}
// или
interface Identifier {
[key: number]: string
}
// или
interface Identifier {
[name: number]: string
}
В одном объектном типе одновременно могут быть объявлены индексные сигнатуры, чьи идентификаторы привязки принадлежат к типу string и типу number. Но — с одной оговоркой. Их типы, указанные в аннотации типов, должны быть совместимы (совместимость типов подробно рассматривается в главах “Типизация — Совместимость объектов” и “Типизация — Совместимость функций”).
[key: string]: string
[key: number]: string
}
let a: A = {
validKeyDeclareStatic: ‘value’, // Ok, значение принадлежит к string
invalidKeyDeclareStatic: 0, // Error, значение должно быть совместимым с типом string
}
a.validKeyDefineDynamicKey = ‘value’ // Ok
a.invalidKeyDefineDynamicKey = 0 // Error, значение должно быть совместимым с типом string
a[0] = ‘value’ // Ok
interface B {
[identifier: string]: string // Ok
[identifier: string]: string // Error, дубликат
}
interface С {
[identifier: string]: string // Ok
[identifier: number]: number // Error, должен принадлежать к типу string
}
class SuperClass {
// суперкласс
a: number
}
class SubClass extends SuperClass {
// подкласс
b: number
}
interface D {
[identifier: string]: SuperClass // Ok
[identifier: number]: SubClass // Ok, SubClass совместим с SuperClass
}
let d: D = {}
d.dynamicKey = new SubClass() // Ok
d[0] = new SubClass() // Ok
interface E {
[identifier: string]: SubClass // Ok
[identifier: number]: SuperClass // Ok, SuperClass несовместим с SubClass
}
Так как классы принадлежат к объектным типам, индексные сигнатуры могут быть объявлены и в них. Все правила, касающиеся индексных сигнатур, которые были рассмотрены ранее и будут рассмотрены далее в этой главе, справедливы и для классов.
[key: string]: string
[key: number]: string
[0]: ‘value’;
[1]: 5 // Error, все члены должны принадлежать к совместимым со string типам
public a: string = ‘value’ // Ok, поле name с типом string
public b: number = 0 // Error, все члены должны принадлежать к совместимым со string типам
public c(): void {} // Error, метод тоже член и на него распространяются те же правила
}
let identifier: Identifier = new Identifier()
identifier.validDynamicKey = ‘value’ // Ok
identifier.invalidDynamicKey = 0 // Error
identifier[2] = ‘value’ // Ok
identifier[3] = 0 // Error
Кроме того, классы накладывают ограничение, которое делает невозможным использовать такие модификаторы, как модификаторы доступа (private, protected, public) и модификаторы, указывающие на принадлежность к уровню класса (static). При попытке указать эти модификаторы при объявлении индексной сигнатуры возникнет ошибка.
public [key: string]: string // Error
}
class B {
static [key: string]: string // Error
}
Но есть несколько нюансов, связанных с модификатором readonly, который подробно рассматривается в главе “Классы — Модификатор readonly”. Чтобы ничего не ускользнуло от понимания, начнем по порядку.
При указании модификатора readonly искажается смысл использования индексной сигнатуры, так как это дает ровно противоположный эффект. Вместо объекта с возможностью инициировать значение указанного типа с динамическими ключами после его создания мы получаем объект, всем членам которого нельзя ничего присвоить. То есть, объект полностью закрыт для изменения.
В случае с интерфейсом:
readonly [key: string]: string // Ok, модификатор readonly
}
let instanceObject: IIdentifier = {}
instanceObject.a // Ok, можно объявить
instanceObject.a = ‘value’ // Error, но нельзя присвоить значение
В случае с классом:
readonly [key: string]: string
}
let instanseClass = new Identifier()
instanseClass.a // Ok, можно объявить
instanseClass.a = ‘value’ // Error, но нельзя присвоить значение
Но это только в теории, и именно с этим связаны оставшиеся нюансы.
Второй нюанс заключается в том, что когда в классе или объекте объявлена индексная сигнатура, становится невозможным объявить в теле или добавить через точечную и скобочную нотацию ключи, ассоциированные с несовместимым типом данных. Это означает, что правило применимое к индексной сигнатуре распространяется на весь объект, как в момент его инициализации, так и после.
В случае с интерфейсом:
[key: string]: string
a: number // Error, [в момент декларации] допускается объявление идентификаторов принадлежащих только к типу string
}
let instanceObject: IIdentifier = {
b: 0, // Error, [в момент объявления] допускается объявление идентификаторов принадлежащих только типу string
}
instanceObject.c = 0 // Error, [после объявления] допускается объявление идентификаторов принадлежащих только типу string
В случае с классом:
readonly [key: string]: string
a: number // Error, [в момент объявления] допускается объявление идентификаторов принадлежащих только типу string
}
let instanseClass = new Identifier()
instanseClass.b = 0 // Error, [после объявления] допускается объявление идентификаторов принадлежащих только типу string
Но в случае с модификатором readonly поведение отличается. Несмотря на то, что указывать идентификаторы членов, принадлежащие к несовместимым типам, по-прежнему нельзя, допускается их декларация и объявление.
В случае с интерфейсом:
readonly [key: string]: string // Ok
a: string // Ok, декларация
}
let instanceObject: IIdentifier = {
a: », // Ok, реализация
b: », // Ok, объявление
}
instanceObject.с = ‘value’ // Error, ассоциировать ключа со значением после создания объекта по прежнему нельзя
В случае с классом:
readonly [key: string]: string
a: string = ‘value’ // Ok, декларация и объявление
}
let instanseClass = new Identifier()
instanseClass.b = ‘value’ // Error, ассоциировать ключа со значением после создания объекта по прежнему нельзя
Такая особенность или даже неочевидность существует, и о ней просто нужно знать. Кроме того, из этой особенности берет начало другая особенность.
Третий нюанс заключается в том, что значения ассоциированные с идентификаторами, которые были задекларированы в типе, можно перезаписать после инициализации объекта.
В случае с интерфейсом:
readonly [key: string]: string // Ok
a: string // Ok, декларация
}
let instanceObject: IIdentifier = {
a: ‘value’, // Ok, реализация
b: ‘value’, // Ok, объявление
}
instanceObject.a = ‘new value’ // Ok, можно перезаписать значение
instanceObject.b = ‘new value’ // Error, нельзя перезаписать значение
В случае с классом:
readonly [key: string]: string
a: string = ‘value’ // Ok, декларация и объявление
}
let instanseClass = new Identifier()
instanseClass.a = ‘new value’ // Ok, можно перезаписать значение
Если учесть, что модификатор readonly вообще не стоит применять к индексной сигнатуре, то все эти нюансы вообще можно выкинуть из головы. Но так цель этой книги защитить читателя от как можно большего количества подводных камней, я решил включить это, так как знание — лучшая защита.
Кроме того, не будет лишним знать наперед, что если идентификатор привязки принадлежит к типу string, то в качестве ключа может быть использовано значение, принадлежащее к типам string, number, symbol, Number Enum и String Enum.
[key: string]: number
}
enum NumberEnum {
Prop = 0,
}
enum StringEnum {
Prop = ‘prop’,
}
let example: StringDynamicKey = {
prop: », // Ok String key
»: », // Ok String key
1: », // Ok Number key
[Symbol.for(‘key’)]: », // Ok Symbol key
[NumberEnum.Prop]: », // Ok Number Enum key
[StringEnum.Prop]: », // Ok String Enum key
}
В случае, когда идентификатор привязки принадлежит к типу number, то значение, используемое в качестве ключа, может принадлежать к таким типам, как number, symbol, Number Enum и String Enum.
[key: number]: number
}
enum NumberEnum {
Prop = 0,
}
enum StringEnum {
Prop = ‘prop’,
}
let example: NumberDynamicKey = {
prop: », // Error String key
»: », // Error String key
1: », // Ok Number key
[Symbol.for(‘key’)]: », // Ok Symbol key
[NumberEnum.Prop]: », // Ok Number Enum key
[StringEnum.Prop]: », // Ok String Enum key
}
Теперь давайте рассмотрим, как такой механизм, как вывод типов, в некоторых случаях выводит тип, принадлежащий к объектному типу с индексной сигнатурой.
Напомню, что в JavaScript, помимо привычного способа при объявлении идентификаторов, в объектных типах можно использовать строковые литералы и выражения, заключённые в фигурные скобки.
let v = {
a: », // объявление идентификатора привычным способом,
[‘b’]: », // объявление идентификатора с помощью строкового литерала.
[‘c’ + ‘d’]: », // объявление идентификатора с помощью выражения со строковыми литералами
[computedIdentifier]: », // объявление идентификатора при помощи вычисляемого идентификатора
}
В первых двух случаях, вывод типов выводит ожидаемый тип. А в оставшихся случаях, вывод типов выводит тип, содержащий индексную сигнатуру.
// let v1: { a: string; }
a: ‘value’, // Ok, привычный идентификатор
}
v1.b = ‘value’ // Error, в типе { a: string } не задекларировано идентификатора b
// let v2: { [‘a’]: string; }
[‘a’]: ‘value’, // Ok, строковый литерал
}
v2.b = ‘value’ // Error, в типе { [‘a’]: string } не задекларировано идентификатора b
let v3 = {
// let v3: { [x: string]: string }; — вывод типов выводит как тип с индексной сигнатурой…
[computedIdentifier]: ‘value’, // вычисляемое свойство
}
v3.b = ‘value’ // … а это, в свою очередь, позволяет добавлять новое значение
// let v4: { [x: string]: string }; — вывод типов выводит как тип с индексной сигнатурой…
[‘a’ + ‘b’]: ‘value’, // выражение со строковыми литералами
}
v4.b = ‘value’ // … а это, в свою очередь, позволяет добавлять новое значение
Индексные выражения
Синтаксис:
<выражение1>[<выражение2>]
Здесь квадратные скобки являются символами языка Си, а не элементами описания.
Значение индексного выражения находится по адресу, который вычисляется как сумма значений <выражения1> и <выражения2>. Выражение1 должно иметь тип указателя на некоторый тип, например быть идентификатором массива, а выражение2, заключенное в квадратные скобки, должно иметь целый тип. Однако требование синтаксиса состоит лишь в том, чтобы одно из выражений было указателем, а другое имело целый тип; порядок же следования выражений безразличен.
Индексное выражение обычно используется для доступа к элементам массива, однако индексацию можно применить к любому указателю.
Индексное выражение вычисляется путем сложения целого значения со значением указателя (или с адресом массива) и последующим применением к результату операции косвенной адресации. Операция косвенной адресации описана в разделе 4.3.2. Например, для одномерного массива следующие четыре выражения эквивалентны, если а — массив или указатель, а b — целое.
а[b]
*(а + b)
*(b + а)
b[а]
В соответствии с правилами преобразования типов для операции сложения (смотри раздел 4.3.4) целочисленное значение при сложении с указателем (адресом) должно умножаться на размер типа, адресуемого указателем. Предположим, например, что идентификатор line определен как массив типа int. При вычислении выражения line[i], целое значение i умножается на размер типа int. Полученное значение представляет i ячеек типа int. Это значение складывается со значением указателя line, что дает адрес объекта, смещенного на i ячеек типа int относительно line, т.е. адрес i-го элемента line.
Заключительным шагом вычисления индексного выражения является применение к полученному адресу операции косвенной адресации. Результатом является значение i-го элемента массива line.
Следует помнить, что индексное выражение line[0] представляет значение первого элемента массива, так как индексация элементов массива начинается с нуля. Следовательно, выражение line[5] ссылается на шестой по порядку следования в памяти элемент массива.
Доступ к многомерному массиву
Индексное выражение может иметь более одного индекса. Синтаксис такого выражения следующий:
<выражение1>[<выражение2>][<выражение3>]…
Индексное выражение интерпретируется слева направо. Сначала вычисляется самое левое индексное выражение — <выражение1>[<выражение2>]. С адресом, полученным в результате сложения <выражения1> и <выражения2>, складывается (по правилам сложения указателя и целого) <выражение3> и т. д. <ВыражениеЗ> и последующие <выражения> имеют целый тип. Операция косвенной адресации осуществляется после вычисления последнего индексного выражения. Однако, если значение последнего указателя адресует значение типа массив, операция косвенной адресации не применяется (смотри третий и четвертый примеры ниже).
Выражения с несколькими индексами ссылаются на элементы многомерных массивов. Многомерный массив в языке Си понимается как массив, элементами которого являются массивы. Например, элементами трехмерного массива являются двумерные массивы.
Примеры:
int рrор[3][4][6];
int i, *ip, (*ipp)[6];
i = prop[0][0][1]; /* пример 1 */
i = prop[2][1][3]; /* пример 2 */
ip = prop[2][1]; /* пример 3 */
ipp = prop[2]; /* пример 4 */
Массив с именем prop содержит 3 элемента, каждый из которых является двумерным массивом значений типа int. В примере 1 показано, каким образом получить доступ ко второму элементу (типа int) массива prop. Поскольку массив заполняется построчно, последний индекс меняется наиболее быстро. Выражение prop[0][0][2] ссылается на следующий (третий) элемент массива и т. д.
Во втором примере выражение вычисляется следующим образом:
1) Первый индекс 2 умножается на размер двумерного массива (4 на 6), затем на размер типа int и прибавляется к значению указателя prop. Результат будет указывать на третий двумерный массив (размером 4 на 6 элементов) в трехмерном массиве prop.
2) Второй индекс 1 умножается на размер 6-элементного массива типа int и прибавляется к адресу, представляемому выражением prop[2].
3) Каждый элемент 6-элементного массива имеет тип int, поэтому индекс 3 умножается на размер типа int и прибавляется к адресу, представляемому выражением prop[2][1]. Результирующий указатель адресует четвертый элемент массива из шести элементов.
4) На последнем шаге вычисления выражения рrор[2][1][3] выполняется косвенная адресация по указателю. Результатом является элемент типа int, расположенный по вычисленному адресу.
В примерах 3 и 4 представлены случаи, когда косвенная адресация не применяется. В примере 3 выражение prop[2][1] представляет указатель на массив из шести элементов в трехмерном массиве prop. Поскольку значение указателя адресует массив, операция косвенной адресации не применяется. Аналогично, результатом вычисления выражения prop[2] в примере 4 является значение указателя, адресующего двумерный массив.
Следующая глава >
Похожие главы из других книг:
Индексные дескрипторы
Индексный дескриптор, или inode, содержит информацию о файле, необходимую для обработки данных, т.е. метаданные файла. Каждый файл ассоциирован с одним inode, хотя может иметь несколько имен в файловой системе, каждое из которых указывает на один и тот же
Виртуальные индексные дескрипторы
Дисковый файл обычно имеет связанную с структуру данных, называемую метаданными или inode, где хранятся основные характеристики данного файла и с помощью которой обеспечивается доступ к его данным. Одним из исключений из этого правила
2.5 Индексные дескрипторы
Файл имеет несколько атрибутов: имя, содержимое и служебную информацию (права доступа и даты модификации). Служебная информация размещается в индексном дескрипторе вместе с важной системной информацией, такой, как размер файла, место хранения
16.3. Индексные дескрипторы файлов
Каждому файлу на диске соответствует один и только один индексный дескриптор файла, который идентифицируется своим порядковым номером — индексом файла. Это означает, что число файлов, которые могут быть созданы в файловой системе,
R.17.2 Выражения
выражение: выражение-присваивания выражение , выражение-присваиваниявыражение-присваивания: выражение-условия унарное-выражение операция-присваивания выражение-присваиванияоперация-присваивания: один из = *= /= %= += -= ››= ‹‹= &= ^=
Выражения
Выражение представляет собой объединение операций и операндов. (Напомним, что операндом называется то, над чем выполняется операция.) Простейшее выражение состоит из одного операнда, отталкиваясь от него, вы можете строить более сложные конструкции.
ВЫРАЖЕНИЯ
Введение
Выражение — это комбинация операндов и операций, задающая порядок вычисления некоторого значения. Операции определяют действия, выполняемые над операндами. Операнд в простейшем случае является константой или переменной. В общем случае каждый
4. Выражения
В главе 3 мы рассмотрели типы данных – как встроенные, так и предоставленные стандартной библиотекой. Здесь мы разберем предопределенные операции, такие, как сложение, вычитание, сравнение и т.п., рассмотрим их приоритеты. Скажем, результатом выражения 3+4*5
Выражения
Многие из задач, которые, так или иначе, выполняются во время преобразования, связаны с вычислением выражений. Для этих целей в XSLT используется язык XPath, который помимо выбора множеств узлов дерева может также выполнять некоторые основные операции над
7. Выражения
Приоритет операций в выраженях такой же, как и порядок главных подразделов в этом разделе, наибольший приоритет у первого. Так например, выражения, о которых говорится как об операндах операции + (#7.4) – это те выражения, которые опрделены в ##7.1-7.4. Внутри каждого
Индексные свойства
Индексные свойства ведут себя аналогично полям-массивам и используются, как правило, для доступа к элементам контейнеров. Как и при использовании обычных свойств, при использовании индексных свойств могут попутно выполняться некоторые
Выражения
Выражение задает вычисление, вырабатывающее значение, — объект или ссылку на объект. Выражениями являются:[x]. неименованные (манифестные) константы;[x]. сущности (атрибуты, локальные сущности, формальные аргументы, Result);[x]. вызовы функций;[x]. выражения с