Ответ 1
в новом принятом предложении 0042-flatten-method-type, self
больше не передается как функция с картой, поэтому эта проблема решена в Swift 3
Я только что узнал, что функция mutating func - это всего лишь функция curried с первым параметром как inout, поэтому приведенный ниже код будет работать и изменить firstName
на "John"
struct Person {
var firstName = "Matt"
mutating func changeName(fn: String) {
firstName = fn
}
}
var p = Person()
let changer = Person.changeName
changer(&p)("John")
p.firstName
но странная вещь, когда я добавляю наблюдателя свойств к p
, как показано ниже, вы можете видеть, что firstName
по-прежнему "Мэтт", почему?
в новом принятом предложении 0042-flatten-method-type, self
больше не передается как функция с картой, поэтому эта проблема решена в Swift 3
Интересная заметка о том, что наблюдатель называется до того, как теневой сеттер называется:
struct Person {
var firstName = "Matt"
mutating func changeName(fn: String) {
firstName = fn
}
}
var p: Person = Person() {
didSet {
print("p was set")
}
}
print("1: \(p.firstName)")
let changer = Person.changeName
print("2: \(p.firstName)")
let setter = changer(&p)
print("3: \(p.firstName)")
setter("John")
print("4: \(p.firstName)")
p.changeName("John")
print("5: \(p.firstName)")
Отпечатки:
1: Matt
2: Matt
p was set
3: Matt
4: Matt
p was set
5: John
Итак, кажется, что приобретение метода setter на inout struct выполняет фактическую мутацию. Это объясняется тем, что параметры inout
работают семантически: когда параметр передается функции, его значение копируется в место, где функция может его мутировать. Когда функция возвращается, значение копируется обратно в исходное место, запуская наблюдателей сеттера один раз, изменилось ли значение или нет.
Когда мы изменим способ получения предварительно заполненного карточного ридера:
let setter = p.changeName
... объекты компилятора:
error: partial application of 'mutating' method is not allowed
Кажется, что компилятор понимает, что закрытие значения inout - плохая идея, так как в основном используется ссылка на тип значения.
Закрытие позволит вам изменить значение структуры в любое время, даже когда компилятор предполагает, что он будет постоянным. Чтобы предотвратить эту неудачную ситуацию, компилятор просто запрещает закрытие входа inout.
Вы нашли случай, который обманывает компилятор и работает вокруг диагностики. Это, кажется, ошибка, и она должна быть подана.
Краткая версия:
struct Foo {
mutating func foo() {}
}
var f = Foo()
let m = Foo.foo
let s = m(&f)
Одна из двух последних строк должна испускать ошибку, похожую на let x = f.foo
.