Swift: how can String.join() work custom types?

后端 未结 6 511
感动是毒
感动是毒 2020-12-30 02:43

for example:

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

Is it possible to make the join function return \"1,2,3\

相关标签:
6条回答
  • 2020-12-30 03:20

    Even if you can't make join work for custom types, there's an easy workaround. All you have to do is define a method on your class (or extend a built-in class) to return a string, and then map that into the join.

    So, for example, we could have:

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

    Then you can do:

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

    I wouldn't recommend using .description for this purpose, as by default it will call .debugDescription, which is not particularly useful in production code.

    In any case, it would be better to provide an explicit method for transforming into a string suitable for joining, rather than relying on a generic 'description' method which you may change at a later date.

    0 讨论(0)
  • 2020-12-30 03:22

    A Swift 3 solution

    public extension Sequence where Iterator.Element: CustomStringConvertible {
        func joined(seperator: String) -> String {
            return self.map({ (val) -> String in
                "\(val)"
            }).joined(separator: seperator)
        }
    }
    
    0 讨论(0)
  • 2020-12-30 03:23

    And just to make your life more complete, starting from Xcode 8.0 beta 1 in Swift 3 you should NOW use [String].joined(separator: ",").

    This is the new "ed/ing" naming rule for Swift APIs:

    Name functions and methods according to their side-effects

    • Those without side-effects should read as noun phrases, e.g. x.distance(to: y), i.successor().
    • Those with side-effects should read as imperative verb phrases, e.g., print(x), x.sort(), x.append(y).
    • Name Mutating/nonmutating method pairs consistently. A mutating method will often have a nonmutating variant with similar semantics, but that returns a new value rather than updating an instance in-place. Swift: API Design Guidelines
    0 讨论(0)
  • 2020-12-30 03:30

    From Xcode 7.0 beta 6 in Swift 2 now you should use [String].joinWithSeparator(",").
    In your case you still need to change Int to String type, therefore I added map().

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

    From Xcode 8.0 beta 1 in Swift 3 code slightly changes to [String].joined(separator: ",").

    var s3 = a.map { String($0) }.joined(separator: ",")    // "1,2,3"
    
    0 讨论(0)
  • 2020-12-30 03:36

    try this

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

    or add this extension

    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 is defined as

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

    which means it takes a sequence of string, you can't pass a sequence of int to it.

    0 讨论(0)
  • 2020-12-30 03:37

    The simplest way is a variation of @BryanChen's answer:

    ",".join(a.map { String($0) } )
    
    0 讨论(0)
提交回复
热议问题