2016-09-21 2 views
1

Я хотел бы написать какую-то беглоподобную api с пользовательскими операторами и функциями. Вот пример того, что я ищу:Swift бегло-подобный дизайн api с пользовательскими операторами

var result = [Section]() 

result +++= Section() 
    .appendTitle(title) 
    .appendPhotos(photos) 

result +++= Section() 
    .appendSomething(sth) 
    .appendPhotos(photos) 
    .appendAnything() 

return result 

Чтобы сделать это, я объявил два пользовательских операторов:

infix operator +++{ associativity left precedence 95 } 

funC+++(lhs : [Section], rhs : Section) -> [Section] { 
    var result = lhs 
    result.append(rhs) 
    return result 
} 

infix operator +++= { associativity left precedence 95 } 

funC+++=(inout lhs : [Section], rhs : Section) { 
    lhs = lhs +++ rhs 
} 

И, конечно, правильное расширение для Section структуры:

extension Section { 
    mutating func appendTitle(title: String?) -> Section { 
     guard let unwrappedTitle = title 
      else { return self } 

     ... 

     return self 
    } 

    mutating func appendPhotos(photos: [Photo]?) -> Section { 
     ... 
    } 

    ... 
} 

К сожалению, это не работает, как ожидалось ...

линия result +++= Section() один правильный, но когда я добавляю .append, он не компилируется.

Первое сообщение: Passing value of type '[Section]' to an inout parameter requires explicit '&'

Затем я попытался поставить & перед result (но я никогда не делал это для a += 1) есть второе сообщение: Cannot use mutating member on immutable value: function call returns immutable value

Так что, если кто-нибудь может помощь, было бы очень признательно.

Я использую Swift 2.2 и Xcode 7.

ответ

3

Ну, вы нашли решение. Замечательно!

Но, пожалуйста, позвольте мне объяснить, что на самом деле произошло здесь.

Давайте подробнее рассмотрим вашу предыдущую реализацию.

extension Section { 
    mutating func appendTitle(title: String?) -> Section { 

     guard let unwrappedTitle = title else { return self } 
     self.title = unwrappedTitle 
     return self 
    } 

    mutating func appendPhotos(photos: [Photo]?) -> Section { 
     guard let unwrappedPhotos = photos else { return self } 
     self.photos = unwrappedPhotos 
     return self 
    } 
} 

Мы знаем (по крайней мере сейчас), что функции перегрузки оператора абсолютно прекрасны, ничего страшного нет.

Данное расширение изменяет значения параметра, поэтому оно должно быть мутирующим, и это так. Тогда почему ошибка:

«Невозможно использовать мутирует элемент на неизменном значении: вызов функции возвращает неизменяемого значение»

Причины: Когда «appendTitle» или «appendPhotos» вызываются, она возвращает копия себя. Не точная ссылка!

Это связано с тем, что быстрые сделки связаны с неизменностью. Если значение для свойства member изменяется для типа значения, создается копия с присвоением значения соответствующему члену.

Таким образом, когда вы пишете: Section().appendTitle(title).appendPhotos(photos)

Section() возвращает копию себя т.е. неизменяемой версии раздела. Поэтому нельзя использовать appendTitle или не может его мутировать в целом.

Это может быть решена:

var section = Section() section.appendTitle(title).appendPhotos(photos)

appendTitle(title) Но теперь возвращает копию себя т.е. неизменяемой версии раздела. и такая же проблема сохраняется.

Вы сделали то, что вместо изменения чего-либо с помощью self вы создали новый экземпляр, на этот раз измененный с использованием var. Мутировал его и вернул. Теперь это не мутирует себя, поэтому не обязательно должно быть mutating func.

Решение, которое вы предоставили, хорошо работает здесь, но на самом деле это хак, который необходим здесь, чтобы покрыть то, что я сейчас скажу «ошибка» в Swift.

Другие решения могут быть изменены struct Section - class Section. Там вам не нужно будет создавать var result, просто измените свойства и верните их.

Это мой первый ответ на SO :)

+0

Спасибо за ваш ответ, что это общая проблема в скор, из-за лет объектно-ориентированного программирования, мы обычно (или, по крайней мере, частично) забывают, что передача параметров по значению а не по ссылке иногда приводит к непониманию языка. Спасибо в любом случае, и поскольку это ваш первый ответ, я с гордостью соглашусь с ним, потому что он намного более явный, чем мой. ;) – Zaphod

+0

@ Zaphod, вы сделали действительно хороший момент. С годами ООП очень легко учесть особенности функциональных языков. Swift - это функциональный язык, и все дело в неизменности. Спасибо, что согласился. :) – Gurdeep

0

Я нашел его !!!

Эти методы не должны были мутирует:

func appendTitle(title: String?) -> Section { 
    guard let unwrappedTitle = title 
     else { return self } 

    var result = self 

    ... // Work with result instead of self!!! 

    return result 
}