Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.0k views
in Technique[技术] by (71.8m points)

swift - Confusing error: Optionality of map's variable changes it from single object to array

I have:

private var wrappedObjects: [WrapperClass]?

var objects: [SomeClass]?
{
    didSet
    {
        self.wrappedObjects = objects.map{ WrapperClass($0) }
    }
}

This results in the following error:

`Cannot convert value of type '[SomeClass]' to expected argument type 'SomeClass'`

However when I just change one line to:

var objects: [SomeClass] = []

the error is gone.

Why does the optionality of objects makes map think $0 is either a single SomeClass or an array [SomeClass] respectively?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

The problem here is that there are two map(_:) functions. One for sequences:

public protocol Sequence {
    // ...

    /// Returns an array containing the results of mapping the given closure
    /// over the sequence's elements.
    /// 
    /// - Parameter transform: A mapping closure. `transform` accepts an
    ///   element of this sequence as its parameter and returns a transformed
    ///   value of the same or of a different type.
    /// - Returns: An array containing the transformed elements of this
    ///   sequence.
    func map<T>(_ transform: (Iterator.Element) throws -> T) rethrows -> [T]

    // ...
}

and one for optionals:

public enum Optional<Wrapped> : ExpressibleByNilLiteral {
    // ...

    /// Evaluates the given closure when this `Optional` instance is not `nil`,
    /// passing the unwrapped value as a parameter.
    ///
    /// - Parameter transform: A closure that takes the unwrapped value
    ///   of the instance.
    /// - Returns: The result of the given closure. If this instance is `nil`,
    ///   returns `nil`.
    public func map<U>(_ transform: (Wrapped) throws -> U) rethrows -> U?

    // ...
}

Therefore when you call map on a [SomeClass]?, the second map function will be used, where the transformation function parameter will be of type [SomeClass], as map will unwrap it for you, and apply a given transformation to it.

However, when you call map on a [SomeClass], the first map function will be used, where the elements will be iterated through – applying the transformation function to each of them. Therefore the parameter type of the transformation function will be SomeClass.

One amusing solution therefore would be to use map twice – once to unwrap, once to apply a transform to the elements:

self.wrappedObjects = objects.map{ $0.map{ WrapperClass($0) } }

However, this is absolutely ridiculous, you should definitely use optional chaining as Rob suggests.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

2.1m questions

2.1m answers

60 comments

57.0k users

...