Конструкция switch-case служит для сравнения выражения с набором значений. Она имеет следующий формат:
После ключевого слова switch в скобках указывается выражение, которое будет сравниваться с каждым значением, заданным после оператора case. При совпадении будет выполнен соответствующий блок case.
Важно отметить, что выражение в switch должно быть одного из целочисленных, символьных типов или представлять перечисление (обсуждается далее).
В конце конструкции switch может находиться блок default. Он не является обязательным и выполняется, если ни одно из значений после switch не соответствует ни одному оператору case. Например:
#include <iostream>std::cout << "x is undefined";
}
Чтобы предотвратить выполнение последующих блоков case или default, в конце каждого блока необходимо использовать оператор break. Таким образом, если выражение совпадает с case 2, выполнится оператор break и дальнейшие операторы case будут проигнорированы, что приведет к выводу на консоль строки «x = 2».
Важно всегда использовать оператор break. Без него выполнение блока case продолжится до следующего блока case. Например, если удалить все операторы break:
#include <iostream>std::cout << "x is undefined";
}
В данном случае, поскольку x равно 2, сначала выполнится case 2, затем case 3, а затем и default, что приведет к выводу:
x = 2 x = 3 x is undefined
Совмещение условий
Можно задать один набор инструкций для нескольких меток case:
#include <iostream>std::cout << "x = 1 или 2";
}
Переменные в блоках case
Определение переменных в блоках case возможно, но требует особого подхода. Если переменная объявляется в блоке case, все инструкции блока должны быть заключены в фигурные скобки (для блока default это не обязательно):
#include <iostream>std::cout << "a = " << a;
std::cout << "b = " << b;
std::cout << "c = " << c;
}
Блок switch с инициализацией переменной
В конструкции switch для промежуточных вычислений можно определить переменную. Начиная с C++17, язык поддерживает особую форму switch:
switch(инициализация; выражение) {}
Эта форма также принимает выражение, которое сравнивается с константами case, но перед ним можно определить и инициализировать переменную. Например:
#include <iostream>std::cout << "Результат: " << (n + k);
std::cout << "Результат: " << (n - k);
}
В данном примере в конструкции switch объявляется переменная k, которая доступна только внутри этой конструкции. Выражение сравнивается с значением переменной op, и в зависимости от этого выполняется соответствующая операция с переменными n и k.
- Глава 1. Введение в С++
- Язык программирования С++
- Первая программа на Windows. Компилятор g++
- Первая программа на Windows. Компилятор Clang
Java 6 представила возможность обнаружения и загрузки реализаций, соответствующих данному интерфейсу, под названием интерфейс поставщика услуг (SPI).
В этом руководстве мы рассмотрим компоненты Java SPI и продемонстрируем, как его можно использовать на практике.
2.1. Обслуживание
Известный набор программных интерфейсов и классов, предоставляющих доступ к конкретным функциям или возможностям приложения.
2.2. Интерфейс поставщика услуг
Интерфейс или абстрактный класс, действующий как прокси или конечная точка для сервиса.
Если сервис представлен единственным интерфейсом, он совпадает с интерфейсом поставщика услуг.
Сервис и SPI вместе образуют API в экосистеме Java.
2.3. Поставщик услуг
Конкретная реализация SPI. Поставщик услуг включает один или несколько классов, реализующих или расширяющих тип сервиса.
Поставщик услуг настраивается и определяется через файл конфигурации, который размещается в каталоге ресурсов META-INF/services. Имя файла соответствует полному имени SPI, а его содержимое — полное имя реализации SPI.
Поставщик услуг устанавливается как расширение, jar-файл, который добавляется в classpath приложения, расширения Java или определенный пользователем путь к классам.
2.4. ServiceLoader
Ключевым компонентом SPI является класс ServiceLoader. Он отвечает за обнаружение и ленивую загрузку реализаций провайдеров, используя контекстный classpath для поиска реализаций и их кэширования.
4.1. Создание нашего API
Начнем с создания проекта Maven под названием exchange-rate-api. Хорошей практикой является окончание имени на api, но можно выбрать любое другое название.
Далее создадим модельный класс для представления валютных курсов:
package com.example.rate.api; public class Quote
Затем определим Service для получения котировок, создав интерфейс QuoteManager:
package com.example.rate.api; public interface QuoteManager { List<Quote> getQuotes(String baseCurrency, LocalDate date); }
Теперь создадим SPI для нашего сервиса:
package com.example.rate.spi; public interface ExchangeRateProvider
В завершение нам нужно создать вспомогательный класс ExchangeRate.java, который будет использоваться клиентским кодом. Этот класс будет делегировать работу ServiceLoader.
Сначала вызываем статический фабричный метод load(), чтобы получить экземпляр ServiceLoader:
ServiceLoader loader = ServiceLoader.load(ExchangeRateProvider.class);
Затем используем метод iterate() для поиска и получения всех доступных реализаций.
Iterator iterator = loader.iterator();
Результат поиска кэшируется, поэтому для обнаружения недавно добавленных реализаций можно вызвать метод ServiceLoader.reload():
loader.reload();
public class ExchangeRate {ServiceLoader loader = ServiceLoader.load(ExchangeRateProvider.class);
public Iterator providers(boolean refresh) {
}
Теперь, когда у нас есть сервис для получения всех установленных реализаций, мы можем использовать их все в нашем клиентском коде для расширения нашего приложения или только одну, выбрав предпочтительную реализацию.
Важно отметить, что этот вспомогательный класс не обязательно должен быть частью проекта API. Клиентский код может самостоятельно вызывать методы ServiceLoader.
4.2. Создание провайдера услуг
Создадим проект Maven с именем exchange-rate-impl и добавим зависимость API в pom.xml:
com.example exchange-rate-api 1.0.0-SNAPSHOT
Теперь создаем класс, который реализует наш SPI:
public class YahooFinanceExchangeRateProvider implements ExchangeRateProvider {return new YahooQuoteManagerImpl();
}
А вот реализация интерфейса QuoteManager:
public class YahooQuoteManagerImpl implements QuoteManager {public List getQuotes(String baseCurrency, LocalDate date) {
}
Чтобы быть обнаруженным, создадим файл конфигурации провайдера:
META-INF/services/com.example.rate.spi.ExchangeRateProvider
Содержимое файла должно содержать полное имя класса реализации SPI:
com.example.rate.impl.YahooFinanceExchangeRateProvider
4.3. Объединение компонентов
Создадим клиентский проект под названием exchange-rate-app и добавим зависимость exchange-rate-api в пути классов:
com.example exchange-rate-api 1.0.0-SNAPSHOT
Теперь можно вызывать SPI из нашего приложения:
ExchangeRate.providers().forEach(provider -> provider.create());
4.4. Запуск приложения
Сосредоточимся на сборке всех наших модулей:
mvn clean package
Запускаем наше приложение с помощью Java без использования провайдера:
java -cp ./exchange-rate-api/target/exchange-rate-api-1.0.0-SNAPSHOT.jar:./exchange-rate-app/target/exchange-rate-app-1.0.0-SNAPSHOT.jar com.example.rate.app.MainApp
Теперь включим нашего провайдера в расширение java.ext.dirs и снова запустим приложение:
java -Djava.ext.dirs=$JAVA_HOME/jre/lib/ext:./exchange-rate-impl/target:./exchange-rate-impl/target/depends -cp ./exchange-rate-api/target/exchange-rate-api-1.0.0-SNAPSHOT.jar:./exchange-rate-app/target/exchange-rate-app-1.0.0-SNAPSHOT.jar com.example.rate.app.MainApp
Мы видим, что наш провайдер загружен.
Что такое SPI
SPI, или Serial Peripheral Interface, представляет собой последовательный интерфейс периферийных устройств. Этот протокол последовательной связи был разработан компанией Motorola в 1970 году. Интерфейс SPI позволяет передавать и получать данные одновременно благодаря полному дуплексному соединению. Это значит, что ведущий (master) может отправлять данные ведомому (slave), который, в свою очередь, может одновременно отправлять данные ведущему. SPI — это синхронный протокол, что означает необходимость синхронизации всех устройств. Ранее мы рассматривали использование этого интерфейса для подключения графического ЖК дисплея Nokia 5110 к плате Arduino.
Как работает интерфейс SPI
Для работы по принципу ведущий/ведомый (master/slave) протокол SPI использует 4 линии. В этом протоколе всегда один ведущий и несколько ведомых. Ведущим устройством обычно является микроконтроллер, а ведомыми могут быть микроконтроллеры, датчики, АЦП, ЦАП, ЖК дисплеи и другие устройства.
Ниже показан принцип работы протокола SPI с одним ведущим (Master) и одним ведомым (Slave).
Для своей работы SPI использует 4 линии: MISO, MOSI, SCK и SS. Их назначение:
- MISO (Master In Slave Out) – линия для передачи данных от ведомого к ведущему;
- MOSI (Master Out Slave In) – линия для передачи данных от ведущего к ведомому;
- SCK (Serial Clock) – линия для передачи синхронизирующих импульсов, формируемых ведущим;
- SS (Slave Select) – линия для включения и выключения определенных устройств (ведомых).
Ниже представлен принцип работы протокола SPI с одним ведущим (Master) и несколькими ведомыми (Slave).
Для начала связи между ведущим и ведомым необходимо установить на контакте ведомого Slave Select (SS) низкий уровень напряжения, чтобы он мог взаимодействовать с ведущим. Когда на этом контакте высокий уровень напряжения, ведомый игнорирует ведущего. Это позволяет подключить множество ведомых устройств к одним и тем же линиям MISO, MOSI и SCK ведущего устройства. Как видно из схемы, для 4-х ведомых устройств линии SCLK, MISO и MOSI общие, а линии SS каждого ведомого подключены к отдельным контактам SS (SS1, SS2, SS3, SS4) ведущего. Устанавливая на нужном контакте SS низкий уровень напряжения (LOW), ведущий может взаимодействовать с необходимым ведомым.
Контакты SPI на плате Arduino Uno
На следующем изображении красным прямоугольником отмечены контакты на плате Arduino Uno, которые могут быть использованы для связи по протоколу SPI.
SPI интерфейс | Пин Arduino Uno |
MOSI | 11 или ICSP-4 |
MISO | 12 или ICSP-1 |
SCK | 13 или ICSP-3 |
SS | 10 |
С контактами разобрались, идем дальше.
Описание программы для Arduino
Нам потребуются две программы: одна – для ведущей платы Arduino, другая – для ведомой платы. Коды обеих программ приведены в конце статьи, а здесь мы кратко обсудим их ключевые части.
Программа для ведущей платы Arduino (Master)
1. Вначале программы необходимо подключить библиотеку SPI, чтобы использовать функции этого протокола.
Что такое SPI?
SPI расшифровывается как Serial Peripheral Interface. Это протокол синхронной последовательной передачи данных. Он используется для связи между периферийными устройствами, такими как входные и выходные устройства, и микроконтроллерами. SPI позволяет передавать данные на высокой скорости. Он популярен в цифровых коммуникационных приложениях и встроенных системах. SPI может передавать и получать данные между устройствами одновременно.
Компоненты SPI
Serial Peripheral Interface (SPI) – это процесс синхронного последовательного протокола передачи данных. Он в основном используется для подключения микроконтроллеров к периферийным устройствам, таким как датчики, дисплеи и чипы памяти. SPI обеспечивает полнодуплексную, синхронную последовательную связь между одним или несколькими ведомыми устройствами и микроконтроллером.