Swift: как String.join() может работать с пользовательскими типами?

например:

var a = [1, 2, 3]    // Ints
var s = ",".join(a)  // EXC_BAD_ACCESS

Можно ли вернуть функцию соединения "1,2,3"?

Расширить Int (или другие настраиваемые типы), чтобы соответствовать некоторым протоколам?

Ответ 1

попробуйте это

var a = [1, 2, 3]    // Ints
var s = ",".join(a.map { $0.description })

или добавьте это расширение

extension String {
    func join<S : SequenceType where S.Generator.Element : Printable>(elements: S) -> String {
        return self.join(map(elements){ $0.description })
    }

  // use this if you don't want it constrain to Printable
  //func join<S : SequenceType>(elements: S) -> String {
  //    return self.join(map(elements){ "\($0)" })
  //}
}

var a = [1, 2, 3]    // Ints
var s = ",".join(a)  // works with new overload of join

join определяется как

extension String {
    func join<S : SequenceType where String == String>(elements: S) -> String
}

что означает, что он принимает последовательность строк, вы не можете передать ему последовательность int.

Ответ 2

От Xcode 7.0 beta 6 в Swift 2 теперь вы должны использовать [String].joinWithSeparator(",").
В вашем случае вам все равно нужно изменить Int на тип String, поэтому я добавил map().

var a = [1, 2, 3]                                       // [1, 2, 3]
var s2 = a.map { String($0) }.joinWithSeparator(",")    // "1,2,3"

От Xcode 8.0 beta 1 в Swift 3 код слегка меняется на [String].joined(separator: ",").

var s3 = a.map { String($0) }.joined(separator: ",")    // "1,2,3"

Ответ 3

И чтобы сделать вашу жизнь более полной, начиная с Xcode 8.0 beta 1 в Swift 3, вы должны использовать NOW [String].joined(separator: ",").

Это новое правило "ed/ing" для API Swift:

Функции и методы имени в соответствии с их побочными эффектами

  • Те, у кого нет побочных эффектов, следует читать как существительные, например. x.distance(to: y), i.successor().
  • Те, у кого есть побочные эффекты, должны читать как императивные фразы глагола, например print (x), x.sort(), x.append(y).
  • Имя Параметр Mutating/nonmutating последовательно. У мутирующего метода часто будет вариант без мутаций с аналогичной семантикой, но он возвращает новое значение, а не обновляет экземпляр на месте. Swift: Руководство по разработке API

Ответ 4

Самый простой способ - это вариант ответа @BryanChen:

",".join(a.map { String($0) } )

Ответ 5

Даже если вы не можете выполнить совместную работу для пользовательских типов, это простое решение. Все, что вам нужно сделать, это определить метод на вашем классе (или расширить встроенный класс), чтобы вернуть строку, а затем сопоставить ее с объединением.

Так, например, мы могли бы:

extension Int {
    func toString() -> String {
        return "\(self)" // trivial example here, but yours could be more complex
    }

Затем вы можете сделать:

let xs = [1, 2, 3]
let s = join(xs.map { $0.toString() })

Я бы не рекомендовал использовать .description для этой цели, так как по умолчанию он вызывается .debugDescription, что не особенно полезно в производственном коде.

В любом случае было бы лучше указать явный метод преобразования в строку, подходящую для соединения, вместо того чтобы полагаться на общий метод описания, который вы можете изменить позже.

Ответ 6

Решение Swift 3

public extension Sequence where Iterator.Element: CustomStringConvertible {
    func joined(seperator: String) -> String {
        return self.map({ (val) -> String in
            "\(val)"
        }).joined(separator: seperator)
    }
}