Swift говорит на всех языках: гид по интеграции с Python, C и не только

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Зачем Swift'у "знать" другие языки?

Представьте, что вы — шеф-повар в элитном ресторане. У вас есть фирменный нож (Swift) — острый, эргономичный, идеально лежит в руке. Но для того, чтобы разделать рыбу фугу, вам нужен специальный скальпель (C), а для создания идеального мусса — дорогой блендер (Python). Вы же не будете рубить рыбу основным ножом? Вот и в программировании так: интеграция Swift с другими языками — это не признак слабости, а вершина мастерства.

Экосистема Swift стремительно развивается, но она не существует в вакууме. Библиотеки для машинного обучения написаны на Python, высокопроизводительные парсеры — на C, а легаси-код банковской системы — на C++. Умение объединять эти миры открывает перед разработчиком космические возможности. В этой статье мы разберем три ключевых сценария: как подружить Swift с Python, C и C++.

1. Swift + Python: магия PythonKit

Apple не была бы собой, если бы не сделала интеграцию максимально "свифтовой". PythonKit — это фреймворк, который позволяет вызывать Python-код прямо из Swift, будто это родные функции. Установка проста: достаточно добавить зависимость через Swift Package Manager.

Настройка проекта

Добавьте в Package.swift:

let package = Package(
    name: "MySwiftPythonApp",
    dependencies: [
        .package(url: "https://github.com/pvieito/PythonKit.git", branch: "master")
    ],
    targets: [
        .target(name: "MySwiftPythonApp", dependencies: ["PythonKit"])
    ]
)

Пример: считаем числа Фибоначчи

Допустим, у вас есть супер-оптимизированный скрипт на Python для вычисления Фибоначчи. Зачем переписывать его на Swift, если можно вызвать напрямую?

Python-файл (fib.py):

def fib(n):
    a, b = 0, 1
    for _ in range(n):
        a, b = b, a + b
    return a

Swift-код:

import PythonKit

// 1. Загружаем модуль (без .py)
let fibModule = try Python.attemptImport("fib")

// 2. Вызываем функцию
let result = fibModule.fib(10)
print("10-е число Фибоначчи:", result) // Вывод: 55

// 3. Работаем с numpy (если установлен)
let np = Python.import("numpy")
let array = np.array([1, 2, 3, 4])
print(array * 2) // Вывод: [2 4 6 8]

Обратите внимание: Python.attemptImport — это безопасная обертка. Если модуль не найден, вы получите ошибку, а не краш приложения. Интеграция Swift и Python через PythonKit работает как на macOS, так и на Linux (при наличии Python 3.x).

Когда это нужно?

  • Вам нужна библиотека, которой нет на Swift (например, pandas или scikit-learn).
  • Вы пишете серверное приложение на Vapor и хотите использовать Python для ETL-процессов.
  • Вы прототипируете ML-модель на Python, а затем встраиваете её в iOS-приложение.

2. Swift + C: прямой разговор с "железом"

C — это язык-легенда. На нем написаны ядра ОС, драйверы и половина вселенной Unix. Swift спроектирован так, чтобы interoperability с C была максимально безболезненной. Вы можете вызывать функции из любой C-библиотеки, не используя обертки.

Импорт C-функций

Создайте файл bridge.h и пропишите в него нужные заголовки:

// bridge.h
#include <math.h>
#include <string.h>

Теперь в Swift вы можете использовать эти функции напрямую:

// Swift
import Foundation

let angle = 45.0 * .pi / 180.0
let sine = sin(angle) // C-функция из math.h
print("Синус 45°:", sine)

// Работа с указателями
let str = "Hello, C!"
str.withCString { cString in
    let length = strlen(cString) // C-функция
    print("Длина строки:", length)
}

Создание своей C-библиотеки

Допустим, вы написали на C быстрый алгоритм сжатия данных. Чтобы использовать его в Swift, нужно создать модуль.

Файл C (compress.c):

#include "compress.h"

int simple_compress(int value) {
    return value ^ 0xFF; // Примитивная "схема"
}

Заголовочный файл (compress.h):

int simple_compress(int value);

Swift-код:

// Добавьте compress.c в target вашего Xcode-проекта
let original = 42
let compressed = simple_compress(original)
print("Сжатое значение:", compressed) // Вывод: 213

Важно: Swift сам управляет памятью, но при вызове C-функций вы берете ответственность за malloc/free. Используйте UnsafePointer и UnsafeMutablePointer для безопасной работы с указателями.

3. Swift + C++: мост в мир ООП

C++ — это "старший брат" C с классами и шаблонами. Прямой Swift C++ interop появился в Swift 5.9 и стал революцией. Раньше приходилось писать обертки на Objective-C++, теперь всё проще.

Прямой вызов C++ классов

Создайте C++ класс:

// MyClass.hpp
class MyClass {
public:
    MyClass(int value) : value_(value) {}
    int getValue() const { return value_; }
    void setValue(int v) { value_ = v; }
private:
    int value_;
};

Теперь в Swift (Xcode 15+):

let obj = MyClass(42) // Создаем C++ объект
print(obj.getValue()) // Вывод: 42
obj.setValue(100)
print(obj.getValue()) // Вывод: 100

Swift автоматически генерирует обертку для C++ классов. Однако есть нюансы:

  • Шаблоны (templates) поддерживаются ограниченно.
  • Виртуальные методы работают, но наследование от C++ классов в Swift пока невозможно.
  • Исключения (exceptions) лучше не использовать — перехватывайте их на стороне C++.

Когда это реально спасает?

Представьте, что вам нужно встроить в iOS-приложение библиотеку компьютерного зрения на C++ (например, OpenCV). Раньше это был квест с мостами, теперь — просто импорт и вызов.

4. Продвинутые техники: FFI и Unsafe

Блоги

Рекомендаций по книгам