Подготовил список задач, которые встречались на интервью в 2024 году.

Разделение на грейды условное, можно считать, что это уровень сложности задач.

Junior

Value type vs Reference type

У нас есть структура Calculator

struct Calculator {
    
    var a: Int
    var b: Int
    
    var sum: Int {
        return a + b
    }
    
    init(a: Int, b: Int) {
        self.a = a
        self.b = b
    }
}

Необходимо объяснить, как работает следующий код, и сказать, что будет выведено на экран?

var calculator = Calculator(a: 3, b: 5)
     
let closure1 = { [calculator] in
    print("Result for closure1 is \(calculator.sum)")
}

let closure2 = { [calculator]
    print("Result for closure2 is \(calculator.sum)")
}

let closure3 = { calculator
    print("Result for closure3 is \(calculator.sum)")
}
    
let closure4 = {
    print("Result for closure4 is \(calculator.sum)")
}
    
calculator.b = 20

closure1() 
closure2() 
closure3() 
closure4()

Решение

  1. В замыкании closure1 используется capture list. Поэтому объект calculator, являющийся value type, будет скопирован. Дальнейшее изменение calculator.b = 20 не повлияет на результат выполнения замыкания.
  1. Во втором примере после capture list пропущено ключевое слово in. Компилятор расценит такой код как попытку создать массив от значения calculator. В таком случае мы увидем ворнинг: Expression of type '[Calculator]' is unused. Поскольку копирование значения в этом случае не произойдет, то при вызове замыкания closure2 мы будем иметь дело с уже новым значением переменной b.
  1. Ситуация похожа на предыдущую, и компилятор подсветит, что объект calculator не используется. Variable is unused. В таком случае, значение не будет скопировано, и результат примет уже новое значение переменной b
  1. Четвертое замыкание уже избавилось от ворнингов и работает с оригинальным объектом переменной calculator.

Follow up

Вероятнее всего интервьюер спросит, а что если структуру Calculator поменять на класс?