Содержание


Обзор языка программирования Vala (для среды Gnome)

Часть 3. Расширенные возможности языка Vala

Comments

Серия контента:

Этот контент является частью # из серии # статей: Обзор языка программирования Vala (для среды Gnome)

Следите за выходом новых статей этой серии.

Этот контент является частью серии:Обзор языка программирования Vala (для среды Gnome)

Следите за выходом новых статей этой серии.

Обработка ошибок

Пример обработки ошибок можно видеть в коде программы просмотра текстовых файлов, рассмотренной в предыдущей статье, где существует вероятность возникновения проблемы при открытии заданного файла.

private void open_file( string filename ) 
{
  try 
  {
    string text;
    size_t size;
    FileUtils.get_contents( filename, out text, out size );
    this.text_view.buffer.set_text( text, (int) size );
  } 
  catch( Error e ) 
  {
    stderr.printf( "Ошибка: %s\n", e.message );
  }
}

В конструкции try {} catch {} не видно никаких отличий от аналогов из C++, C# и Java. Особенности обнаруживаются на более низком уровне – в реализации. В библиотеке GLib имеется средство управления исключениями времени выполнения GError. Vala преобразует его в более привычную "современную" форму, но сам по себе GError изначально был предназначен для обработки так называемых восстановимых ошибок времени выполнения, о которых ничего не известно до начала выполнения, и которые не приводят к аварийному завершению программы. Поэтому не следует напрямую использовать GError для тех исключительных ситуаций, которые можно "предсказать", например, передача отрицательного числа в функцию, которая требует параметр только со значением, большим нуля.

При возникновении необходимости в написании специфического кода для обработки исключений общая схема работы точно такая же, как при использовании любого другого языка из "C-группы". Все функции, являющиеся потенциальными источниками исключений, определяются с ключевым словом throws. Везде, где это необходимо в коде, записываются команды генерации исключений throw. Вызовы потенциально "опасных" функций помещаются в блоки try-catch.

Отличия проявляются при определении типов обрабатываемых исключений (ошибок). Исключения обладают тремя характеристиками: домен (domain), код (code) и сообщение (message). Домен определяет тип ошибки. Ближайший аналог – подкласс класса Exception в языке Java. Каждый домен исключения может содержать один или несколько кодов ошибок:

errordomain IOError     // имя домена
{
  FILE_NOT_FOUND        // код ошибки
}

Таким образом, можно определить не только обобщённый тип возникающей проблемы, но и конкретную ошибку. Что касается сообщений, то мы уже встречались с ними – это текст, выводимый при возникновении исключительной ситуации.

Для того чтобы обрабатывать исключения в программе, вы должны определить домены с кодами ошибок и написать соответствующие обработчики для доменов. Каждому домену ошибок соответствует отдельный блок catch. Кроме того, после блока try и всех необходимых блоков catch можно добавить необязательный блок finally, который будет выполняться всегда, даже при отсутствии ошибок и их обработки, потому что иногда требуется освобождение ресурсов, захваченных внутри блока try.

Всё, сказанное выше, можно проиллюстрировать следующим примером:

errordomain ErrType01
{
  ERROR_CODE_01
}

errordomain ErrType02
{
  ERROR_TYPE_02
}

public class MyClass : GLib.Object
{
  public static void myfunc_throw() throws ErrType01, ErrType02
  {
    throw new ErrType01.ERROR_CODE_01( "Ошибка с кодом 01" );
  }

  public static void myfunc_catch() throws ErrType02
  {
    try
    {
      myfunc_throw();
    }
    catch( ErrType01 e )
    {
      // Здесь обрабатываются ошибки из домена ErrType01
    }
    finally
    {
      // Освобождение ресурсов и прочие необходимые операции
    }
  }

  public static int main( string[] args )
  {
    try
    {
      myfunc_catch();
    }
    catch( ErrType02 e )
    {
      // Здесь обрабатываются ошибки из домена ErrType02
    }
    return 0;
  }
}

Здесь метод myfunc_throw может генерировать исключения из обоих доменов, определённых в программе. Метод myfunc_catch способен генерировать исключения только второго типа, поэтому обязан обеспечить обработку ошибок из домена ErrType01. В свою очередь, метод main обеспечивает обработку всех ошибок, которые могут возникать при работе метода myfunc_catch.

Многопоточность

Поток (thread) в языке Vala не определяется во время компиляции, это просто фрагмент кода, который программа во время выполнения будет пытаться выполнить как новый поток. Многопоточность реализована с помощью статических функций класса Thread из библиотеки GLib. Рассмотрим небольшой и очень простой пример.

01: using GLib;
02: public class MyThread : GLib.Object
03: {
04:   public static void * thread_fun()
05:   {
06:     stdout.printf( "Поток активизирован... \n" );
07:     return null;
08:   }
09:   public static int main( string [] args )
10:   {
11:     if( !Thread.supported() )
12:     {
13:       stdout.printf( "Без поддержки потоков выполнение невозможно \n" );
14:       return -1;
15:     }
16:     try
17:     {
18:       Thread.create( thread_fun, false );
19:     } 
20:     catch( ThreadError ex )
21:     {
22:       return -1;
23:     }
24:     return 0;
25:   }
26: }

При компиляции необходимо подключить поддержку многопоточности, используя соответствующий ключ:

valac --thread -o thread-test mythread.vala

Отметим, что исходный код был сохранён в файл mythread.vala, а для конечного выполняемого файла задано другое имя (thread-test) с помощью ключа -o.

Результат работы программы показан на рисунке 1.

Рисунок 1. Выполнение многопоточной программы
Рисунок 1. Выполнение многопоточной программы
Рисунок 1. Выполнение многопоточной программы

Этот пример демонстрирует лишь возможность работы с потоками при программировании на языке Vala. В рамках данной статьи невозможно рассмотреть все аспекты и проблемы многопоточности: синхронизацию, кооперацию потоков и т.д.

Работа с библиотеками

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

valac --pkg gtk+-2.0 text-file-viewer.vala

в программе будут использованы все определения из файла gtk+-2.0.vapi, а также все пакеты (библиотеки), от которых зависит gtk+-2.0. Если такие зависимости существуют, то они перечисляются в файле gtk+-2.0.deps. Всю остальную работу по подключению необходимых C-библиотек компилятор Vala выполняет автоматически, без нашего вмешательства.

С созданием собственных библиотек дело обстоит гораздо сложнее. Мы уже выяснили, что с технической точки зрения "библиотека Vala" означает "C-библиотека". Таким образом, в действительности вам придётся создавать библиотечный файл языка C. Это можно сделать двумя способами. Первый – это получение объектных файлов из исходных кодов Vala с помощью ключа компилятора -c (компилировать, но не связывать):

vala -c <список_vala-файлов>

и последующим использованием системных утилит обслуживания библиотечных файлов ar или комплекта для создания динамических библиотек libtool. Например:

ar rc <имя_библиотеки> <полученные_объектные_файлы>

Второй способ предполагает генерацию промежуточного C-кода (в предыдущей статье мы уже пользовались ключом -C):

valac -C <список_vala-файлов>

и компиляцию полученных после этого файлов с целью получения динамических (shared) библиотек:

gcc -o my-library.so --shared -fPIC <список_полученных_С-файлов>

Здесь ключ -fPIC позволяет сгенерировать позиционно-независимый код (Position-Independent Code), который необходим для создания динамически связываемой библиотеки.

Обзор штатных инструментальных средств и утилит

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

vala-gen-introspect – инструмент для извлечения метаинформации о библиотеках, основанных на GObject. Эта информация может использоваться для создания vapi-файлов, т. е. для привязки библиотеки с целью применения её в Vala-программах. Имя библиотеки должно быть задано в формате pkg-config.

vapigen – создаёт vapi-файлы с помощью метаинформации о библиотеках и прочей дополнительной информации.

vala-gen-project – простая графическая среда для создания Vala-проекта. Созданный в ней проект будет содержать скрипты генерации программ с помощью auto-инструментов (autoconf, automake и проч.), которые могут послужить основой для построения более сложной системы.

Справочную информацию об этих утилитах и о компиляторе можно получить из соответствующих man-страниц.

Заключение

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

vala-gen-introspect – инструмент для извлечения метаинформации о библиотеках, основанных на GObject. Эта информация может использоваться для создания vapi-файлов, т. е. для привязки библиотеки с целью применения её в Vala-программах. Имя библиотеки должно быть задано в формате pkg-config.

vapigen – создаёт vapi-файлы с помощью метаинформации о библиотеках и прочей дополнительной информации.

vala-gen-project – простая графическая среда для создания Vala-проекта. Созданный в ней проект будет содержать скрипты генерации программ с помощью auto-инструментов (autoconf, automake и проч.), которые могут послужить основой для построения более сложной системы.

Справочную информацию об этих утилитах и о компиляторе можно получить из соответствующих man-страниц.


Ресурсы для скачивания


Комментарии

Войдите или зарегистрируйтесь для того чтобы оставлять комментарии или подписаться на них.

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Linux
ArticleID=467176
ArticleTitle=Обзор языка программирования Vala (для среды Gnome): Часть 3. Расширенные возможности языка Vala
publish-date=02092010