Программирование в Scilab Микаэль Боден Micha
Скачать 1.35 Mb.
|
f u n c t i o n t h i s = c o m p a n y _ n e w () t h i s = t l i s t ([ " T C O M P A N Y " , " n am e " , " a d d r e s s " , " p u r p o s e " , " e m p l o y e e s " ]) 41 t h i s . n a m e = " " t h i s . a d d r e s s = " " t h i s . p u r p o s e = " " t h i s . e m p l o y e e s = l i s t () e n d f u n c t i o n Следующая функция company_addperson позволяет добавлять нового человека в список работников. f u n c t i o n t h i s = c o m p a n y _ a d d p e r s o n ( th i s , p e r s o n ) t h i s . e m p l o y e e s ( $ +1) = p e r s o n e n d f u n c t i o n На самом деле, методы, которые широко используются в ООП, могут применяться используя эту схему имитации. Это позволяет создавать отдельные компоненты, предостав- ляющие прозрачный публичный интерфейс и избегающие необходимости в сложных функ- циях, использующих большое количество позиционных аргументов. 3.8 Перегрузка типизированных списков В этом разделе мы увидим как перегрузить функцию string так, что бы мы могли преобразовать типизированный список в строку. Мы также рассмотрим как перегрузить функцию disp, т. е. систему печати, которая позволяет настраивать печать типизированных списков. Следующая функция %TPERSON_string возвращает матрицу строковых значений, со- держащую описание текущего объекта «person». Она сначала создаёт пустую матрицу. За- тем она добавляет строки одну за другой с помощью выходного значения функции sprintf, которая позволяет форматировать строки. f u n c t i o n str = % T P E R S O N _ s t r i n g ( t h i s ) str = [] k = 1 str ( k ) = s p r i n t f ( " P e r s o n : " ) k = k + 1 str ( k ) = s p r i n t f ( " = = = = = = = = = = = = = = = = = = = = = = " ) k = k + 1 str ( k ) = s p r i n t f ( " N a m e : %s " , t hi s . n a m e ) k = k + 1 str ( k ) = s p r i n t f ( " F i r s t n a m e : %s " , t h i s . f i r s t n a m e ) k = k + 1 str ( k ) = s p r i n t f ( " P h o n e : %s " , th i s . p h o n e ) k = k + 1 str ( k ) = s p r i n t f ( " E - m a i l : %s " , t h i s . e m a i l ) e n d f u n c t i o n Функция %TPERSON_string позволяет перегрузить функцию string для любого объекта с типом TPERSON. Следующая функция %TPERSON_p распечатывает текущий объект «person». Она сна- чала вызывает функцию string для того, чтобы вычислить матрицу строк, описывающих объект «person». Затем она делает циклы по рядам матрицы и распечатывает их один за другим в консоли. f u n c t i o n % T P E R S O N _ p ( t h i s ) str = s t r i n g ( th i s ) n b r o w s = s i z e ( str , " r " ) 42 for i = 1 : n b r o w s m p r i n t f ( " %s \ n " , str ( i )) end e n d f u n c t i o n Функция %TPERSON_p позволяет перегрузить распечатку объектов с типом TPERSON (буква «p» обозначает распечатку («print»)). В следующем примере мы вызываем функцию string с объектом «person» p1. - - > p1 = p e r s o n _ n e w (); - - > p1 = p e r s o n _ c o n f i g u r e ( p1 , " - n a m e " , " B a c k u s " ); - - > p1 = p e r s o n _ c o n f i g u r e ( p1 , " - f i r s t n a m e " , " J o h n " ); - - > p1 = p e r s o n _ c o n f i g u r e ( p1 , " - p h o n e " , " 0 1 . 2 3 . 4 5 . 6 7 . 8 9 " ); - - > p1 = p e r s o n _ c o n f i g u r e ( p1 , " - e m a i l " , " j o h n . b a c k u s @ c o m p a n y . com " ); - - > s t r i n g ( p1 ) ans = ! P e r s o n : ! ! ! ! = = = = = = = = = = = = = = = = = = = = = = ! ! ! ! N a m e : B a c k u s ! ! ! ! F i r s t n a m e : J o h n ! ! ! ! P h o n e : 0 1 . 2 3 . 4 5 . 6 7 . 8 9 ! ! ! ! E - m a i l : j o h n . b a c k u s @ c o m p a n y . com ! В предыдущем примере функция string автоматически вызвала функцию %TPERSON_string, которую мы определили ранее. В следующем примере мы просто напечатаем имя переменной p1 (и немедленно на- жмём клавишу enter в консоли), как и с любой другой переменной. Это распечатает содер- жимое нашей переменной p1. - - > p1 p1 = P e r s o n : = = = = = = = = = = = = = = = = = = = = = = N a m e : B a c k u s F i r s t n a m e : J o h n P h o n e : 0 1 . 2 3 . 4 5 . 6 7 . 8 9 E - m a i l : j oh n . b a c k u s @ c o m p a n y . com В предыдущем примере система печати автоматически вызвала функцию %TPERSON_p, ко- торую мы уже определили ранее. Заметим, что будет сделан тот же вывод как если бы мы использовали команду disp(p1). Наконец, мы уничтожим текущий объект «person». p1 = p e r s o n _ f r e e ( p1 ); Есть много других функций, которые могли бы быть определены для типизированных списков. Например, мы можем перегрузить оператор + так, что мы можем суммировать два объекта «person». Это описано более подробно на страницах справки, посвящённых пере- грузке: h e l p o v e r l o a d i n g 43 3.9 Тип данных mlist В этом разделе мы представляем тип данных mlist, который является матрично- ориентированным списком. В первой части этого раздела мы представляем главную мо- тивацию для типа данных mlist сравнивая с tlist. Затем мы представляем пример mlist, где мы определяем функцию выделения. Главная разница между tlist и mlist состоит в отношении к выделению и встав- ке функций. В самом деле, для tlist M выделение, основанное на индексах, т. е. команда x=M(2), например, определена по умолчанию. Она может быть перегружена пользователем, но это не обязательно, как мы увидим далее. В следующем примере мы определяем tlist с типом «V». Этот типизированный список имеет два поля, «name» (имя) и «age» (возраст). M = t l i s t ([ " V " , " n a m e " , " age " ] ,[ " a " , " b " ; " c " " d " ] ,[1 2; 3 4 ] ) ; Как ожидалось от tlist, команда M(2) позволяет выделить второе поле, т. е. «name» (имя) переменной. - - > M (2) ans = ! a b ! ! ! ! c d ! То же самое для вставки (т. е. M(2)=x) в list (или tlist). С другой стороны, для mlist выделение и вставка функций должна быть определена. Если нет, то формируется ошибка. В следующем примере мы определяем mlist с типом «V». Как и прежде, этот список матриц имеет два поля, «name» и «age». M = m l i s t ([ " V " , " n a m e " , " age " ] ,[ " a " , " b " ; " c " " d " ] ,[1 2; 3 4 ] ) ; В следующем примере мы видим, что не можем напрямую выделять второе поле этого списка - - > M (2) ! - - e r r o r 144 Операция для заданных операндов не определена. отметьте или определите функцию % l _ e как перегружаемую. Сообщение об ошибке говорит нам, что мы не можем выделить второй элемент переменной M и что должна быть определена некая функция, которую мы увидим позднее в этом разделе. Давайте рассмотрим предыдущий пример и предположим, что M — это tlist. Особая проблема с M заключается в том, что второй элемент M(2) может не соответствовать тому, что нам надо. В самом деле, переменная M(2) является матрицей строковых переменных ["a","b";"c" "d"]. Но возможны такие ситуации, где нам бы хотелось выразить, что «вто- рой элемент» представляет особый элемент, который не соответствует особому значению, которое связано с tlist. К примеру, мы можем захотеть конкатенировать имя со значением для формирова- ния строки «Name: b, age: 2», которая бы была вторым элементом нашей матрицы M. Сле- довательно, кажется, что нам нужно переопределить выделение (или вставку) значений для tlist. Но это невозможно, поскольку система перегрузки позволяет только определять функции, которые не существуют: в этом случае функция выделения уже существует, так что мы не можем определять её. Это случай, когда полезен mlist: мы можем определить 44 функции выделения и вставки для mlist и настроить их поведение. Фактически, мы даже принуждаем делать так: поскольку, как мы видели до этого, это обязательно. Для того, чтобы определить функцию выделения для mlist с «V», мы должны опреде- лить функцию %V_e, где буква «e» обозначает «extraction» (выделение). Это сделано в следу- ющем примере. Заголовок функции выделения должен быть [x1,...,xm]=% i1,...,in — индексы значений, которые нужно выделить, и a — текущая переменная. Следовательно, команда M=varargin($) позволяет установить в M текущую переменную из которой выделяются значения. Затем индексы могут быть получены с помощью команды varargin(1:$-1), которая создаёт список переменных, содержащий действующие индек- сы. Наконец, мы создаём матрицу строковых переменных конкатенацией имени со строкой, представляющей возраст. f u n c t i o n r = % V _ e ( v a r a r g i n ) M = v a r a r g i n ( $ ) r = " N a m e : " + M . n a m e ( v a r a r g i n (1: $ - 1) ) + .. " , Age : " + s t r i n g ( M . age ( v a r a r g i n (1: $ - 1 ) ) ) e n d f u n c t i o n В следующем примере мы выделяем второй элемент M. - - > M (2) ans = N a m e : c , Age : 3 Мы можем также использовать синтаксис, который очень похож на матрицы, как в следу- ющем примере. - - > M ( 2 : 3 ) ans = ! N a m e : c , Age : 3 ! ! ! ! N a m e : b , Age : 2 ! - - > M (2 ,:) ans = ! N a m e : c , Age : 3 N a m e : d , Age : 4 ! - - > M (: ,1) ans = ! N a m e : a , Age : 1 ! ! ! ! N a m e : c , Age : 3 ! 3.10 Тип данных struct В этом разделе мы кратко представляем struct, которая является структурой данных, с беспорядочными составляющими разнородных типов. Мы сравним её характеристики с list. Внутри struct все составляющие могут быть выделены по их именам. В следующем примере мы определяем переменную d как struct с тремя полями «day» (день), «month» (месяц) и «year» (год ). - - > d = s t r u c t ( " day " ,25 , " m o n t h " , " DEC " , " y e a r " ,2006) d = day : 25 m o n t h : " DEC " y e a r : 2 0 06 45 Заметьте, что поля структуры struct не обязаны быть одного типа: первое поле — это строка, а второе поле число типа double. Для того, чтобы выделить переменную из struct, мы просто используем имя переменной после точки «.» и имя поля. - - > d . m o n t h ans = DEC Для того, чтобы вставить значение в struct, мы просто используем оператор присво- ения «=». - - > d . m o n t h =AUG d = day : 25 m o n t h : " AUG " y e a r : 2 0 06 Структура struct может содержать другую структуру struct, что может привести к структурам вложенных данных. Например, в следующем примере мы создаём уик-энд из двух последовательных дней. - - > d1 = s t r u c t ( " day " ,01 , " m o n t h " , " JAN " , " y e a r " ,2011); - - > d2 = s t r u c t ( " day " ,02 , " m o n t h " , " JAN " , " y e a r " ,2011); - - > w e e k e n d = s t r u c t ( " Sat " , d1 , " Sun " , d2 ) w e e k e n d = Sat : [1 x1 s t r u c t ] Sun : [1 x1 s t r u c t ] - - > w e e k e n d . Sat ans = day : 01 m o n t h : " JAN " y e a r : 2 0 11 С точки зрения гибкости tlist более мощный нежели struct. Это из-за того, что мы можем перегружать функции так, что их поведение может быть настроено для tlist. Дей- ствительно, настройка поведения структуры struct невозможна. Вот почему большинство пользователей предпочитают тип данных tlist. Фактически, главное преимущество struct — это совместимость с Matlab и Octave. 3.11 Массив структур struct Массив структур struct — это массив, где каждый индекс связан со структурой struct. Есть несколько способов создать массив структур. В первой части этого раздела мы конка- тенируем несколько структур для создания массива. Во второй части мы инициализируем целый массив структур за один вызов, а затем заполняем поля одно за другим. Если несколько структур имеют одинаковые поля, и если все эти поля имеют одина- ковый размер, то они могут быть конкатенированы в один массив структур. В следующем примере мы создаём четыре отдельных структуры. s1 = s t r u c t ( " f i r s t n a m e " , " J o h n " , " b i r t h y e a r " ,1940); s2 = s t r u c t ( " f i r s t n a m e " , " P a u l " , " b i r t h y e a r " ,1942); s3 = s t r u c t ( " f i r s t n a m e " , " G e o r g e " , " b i r t h y e a r " ,1943); s4 = s t r u c t ( " f i r s t n a m e " , " R i n g o " , " b i r t h y e a r " ,1940); Заметим, что поля не обязаны быть одного типа: первое поле — строка, а второе поле — число типа double. Затем мы конкатенируем их в один массив структур, используя синтаксис [], который схож с матрицами. 46 - - > s =[ s1 , s2 , s3 , s4 ] s = 1 x4 s t r u c t a r r a y w i t h f i e l d s : f i r s t n a m e n a m e Мы можем выделить третью структуру из массива используя синтаксис s(3), который схож с матрицами. - - > s (3) ans = f i r s t n a m e : " G e o r g e " n a m e : " H a r r i s s o n " Мы можем получить доступ к полю «firstname» всех структур, как показано в следующем примере. Это даёт список строк. - - > s . f i r s t n a m e ans = ans (1) J o h n ans (2) P a u l ans (3) G e o r g e ans (4) R i n g o - - > t y p e o f ( s . f i r s t n a m e ) ans = l i s t По причине производительности мы не советуем позволять структура расти динамиче- ски. Это из-за того, что это заставляет интерпретатор динамически распределять больше и больше памяти и может привести к медленным файлам-сценариям. Вместо этого, где только возможно, нам следует предопределять массивы структур, а затем заполнять существующие ячейки. В следующем примере мы определяем массив размером 4 × 1 структур struct, где каждая структура содержит пустое firstname и пустое name. t ( 1 : 4 ) = s t r u c t ( " f i r s t n a m e " ,[] , " b i r t h y e a r " ,[]) Затем мы заполняем каждую структуру как в следующем примере. t ( 1 ) . f i r s t n a m e = " J o h n " ; t ( 1 ) . b i r t h y e a r = 1 9 4 0 ; t ( 2 ) . f i r s t n a m e = " P a u l " ; t ( 2 ) . b i r t h y e a r = 1 9 4 2 ; t ( 3 ) . f i r s t n a m e = " G e o r g e " ; t ( 3 ) . b i r t h y e a r = 1 9 4 3 ; t ( 4 ) . f i r s t n a m e = " R i n g o " ; t ( 4 ) . b i r t h y e a r = 1 9 4 0 ; Мы можем проверить, что это даёт в точности тот же массив структур, что и прежде. - - > t t = 4 x1 s t r u c t a r r a y w i t h f i e l d s : f i r s t n a m e b i r t h y e a r - - > t (1) 47 ans = f i r s t n a m e : " J o h n " b i r t h y e a r : 1 9 4 0 В предыдущим примерах мы видели только массивы с одним индексом. Должно быть ясно, что массив структур является в действительности 2 х -индексным массивом, т. е. мат- рицей. Кстати, мы собираемся рассмотреть другой метод инициализации массива структур. В следующем примере мы инициализируем массив структур размером 2 × 2. - - > u (2 ,2). f i r s t n a m e =[] u = 2 x2 s t r u c t a r r a y w i t h f i e l d s : f i r s t n a m e - - > u (2 ,2). b i r t h y e a r =[] u = 2 x2 s t r u c t a r r a y w i t h f i e l d s : f i r s t n a m e b i r t h y e a r Затем мы можем заполнить ячейки с помощью синтаксиса, который похож на матрицы. u (1 ,1). f i r s t n a m e = " J o h n " ; u (1 ,1). b i r t h y e a r = 1 9 4 0 ; u (2 ,1). f i r s t n a m e = " P a u l " ; u (2 ,1). b i r t h y e a r = 1 9 4 2 ; u (1 ,2). f i r s t n a m e = " G e o r g e " ; u (1 ,2). b i r t h y e a r = 1 9 4 3 ; u (2 ,2). f i r s t n a m e = " R i n g o " ; u (2 ,2). b i r t h y e a r = 1 9 4 0 ; Сделав однажды, мы можем выделять структуры, связанные с индексами (2,1), например. - - > u (2 ,1) ans = f i r s t n a m e : " P a u l " b i r t h y e a r : 1 9 4 2 3.12 Тип данных cell В этом разделе мы кратко представляем cell, который является разнородным масси- вом переменных. Затем мы сравниваем его характеристики с характеристиками гипермат- рицы hypermatrix и списка list. Рисунок 17 представляет несколько функций, связанных с массивами cell. cell Создать сell-массив с пустыми ячейками. cell2mat Преобразовать cell-массив в матрицу. iscell Проверить, является ли переменная cell-массивом. makecell Создать cell-массив и инициализировать его ячейки. Рис. 17: Функции, связанные с массивами cell. Функция cell позволяет создавать массив. Этот cell-массив может содержать другие типы переменных, включая double, integer, string и т. д. В следующем примере мы создаём cell-массив размером 2 × 3. 48 - - > c = ce l l (2 ,3) c = !{} {} {} ! ! ! !{} {} {} ! Размер cell-массива может быть вычислен с помощью функции size. - - > s i z e ( c ) ans = 2. 3. Для того, чтобы ввести значение в cell-массив, мы не можем использовать тот же синтаксис, что и для матриц. - - > c ( 2 , 1 ) = 1 2 ! - - e r r o r 1 0 0 0 0 I n v a l i d a s s i g n e m e n t : for i n s e r t i o n in cell , use e . g . x ( i , j ). e n t r i e s = y at l i n e 3 of f u n c t i o n g e n e r i c _ i _ c e c a l l e d by : at l i n e 3 of f u n c t i o n % s _ i _ c e c a l l e d by : c ( 2 , 1 ) = 1 2 Вместо этого мы можем использовать поле entries элемента (2,1), как в следующем при- мере. - - > c (2 ,1). e n t r i e s =12 c = !{} {} {} ! ! ! !12 {} {} ! В следующем примере мы вводим строку в элемент (1,3). - - > c (1 ,3). e n t r i e s = " 5 " c = !{} {} " 5 " ! ! ! !12 {} {} ! Для того, чтобы удалить элемент (1,3), мы можем использовать матрицу []. - - > c (1 ,3). e n t r i e s =[] c = !{} {} {} ! ! ! !12 {} {} ! Мы можем выделять часть cell-массива, используя синтаксис, схожий с матрицами. Заметим, что результатом является cell-массив. - - > x = c (1:2 ,1) x = !{} ! ! ! !12 ! - - > t y p e o f ( x ) ans = ce С другой стороны, когда мы выделяем одну конкретную ячейку с помощью поля entries, мы получаем тот же тип данных, что и в данная конкретная ячейка. В следующем примере мы выделяем ячейку (2,1) в переменную x и проверяем, что эта переменная имеет тип double. 49 |