Swift 4.2 - Возвращение классов, созданных внутри функции - PullRequest
0 голосов
/ 09 января 2019

Я хотел объявить фабрику, чтобы помочь мне создавать экземпляры одноэлементных классов для тестирования без дополнительных затрат на очистку состояния уровня класса между запусками теста. Я думал о том, чтобы использовать фабрику для возврата класса, объявленного внутри функции.

Я предполагал, что класс будет создан на лету и будет сохраняться только до тех пор, пока сохраняется возвращаемая ссылка. Например:

protocol TestClassFactory {
    static func make() -> TestClass.Type
}

protocol TestClass {
    static var testValue: String { get set }
}

class Factory: TestClassFactory {
    static func make() -> TestClass.Type {
        class Tester: TestClass {
            static var testValue = "Unmodified"
        }

        return Tester.self
    }
}

Однако на практике это не сработало, как ожидалось. В частности, статическое значение, установленное для первого make() возвращаемого значения, сохраняется во втором.

var testClass1 = Factory.make()
print(testClass1.testValue)        // "Unmodified"
testClass1.testValue = "Modified"
print(testClass1.testValue)        // "Modified"

var testClass2 = Factory.make()
print(testClass2.testValue)        // "Modified" ?

Среда выполнения Swift, похоже, сохраняет класс таким же, как и класс, объявленный и на который ссылаются во время компиляции.

Мои вопросы:

  1. Есть ли у кого-нибудь ссылка, в которой описано, предназначено ли это поведение? Я бы предположил, что это так, но хотел бы знать наверняка.
  2. Для моего конкретного случая использования, есть ли у меня какие-либо варианты, кроме как использовать какое-либо отражение / зеркало для динамической генерации типа?

1 Ответ

0 голосов
/ 09 января 2019

Swift способен создавать новые типы во время выполнения, но я не думаю, что в настоящее время возможно использовать эту возможность в качестве пользователя языка.

В Swift не все операторы являются исполняемыми: есть код, который оценивается только во время компиляции и не приводит к выполнению исполняемого кода. Классовые заявления являются одним из них. Область действия класса не оценивается во время выполнения для создания нового класса: компилятор видит оператор класса, строит этот класс и дает вам статическую ссылку на этот класс в будущем. Таким образом, никакой код не выполняется при запуске вашей программы (или в любое другое время), когда вы создаете класс. Это отличается от других языков, таких как Python, где каждый оператор по своей природе исполняем, а выполнение оператора класса фактически создает класс.

Это поведение подчеркивается ошибками, когда вы пытаетесь использовать локальные переменные внутри функционально-локальных классов:

func foo(int: Int) {
    class Bar {
        let f = int
        // error: class declaration cannot close over value 'int' defined in outer
        // scope
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...