Array extension where Element is Optional and the the return type is Wrapped
I am not sure what you mean with Wrapped<Element>
but since you need to return something why not use a closure for the return value, like this function to get the element at a specific index
extension Array {
func value<T>(at index: Int, emptyAction: () -> T) -> T where Element == T? {
if let value = self[index] {
return value
}
return emptyAction()
}
}
Example
var test = [String?]()
test.append("ABC")
test.append("DEF")
test.append(nil)
for i in 0..<test.count {
print(test.value(at: i, emptyAction: { "<empty>" }))
}
Outputs
ABC
DEF
<empty>
Extension for Array where Element is Optional
This is kind of tricky but you can create an AnyOptional protocol that requires an associatedtype (Wrapped) and a computed property to return the optional type. Then you can return the element unwrapped if the index is valid otherwise return nil.
protocol AnyOptional {
associatedtype Wrapped
var optional: Optional<Wrapped> { get }
}
extension Optional: AnyOptional {
var optional: Optional<Wrapped> { self }
}
extension Collection {
subscript(safe index: Index) -> Element? {
indices.contains(index) ? self[index] : nil
}
}
extension Collection {
subscript(safe index: Index) -> Element.Wrapped? where Element: AnyOptional {
indices.contains(index) ? self[index].optional ?? nil : nil
}
}
var myArray: [String?] = ["2", "banana", nil, "31"]
var myStringArray: [String] = ["2", "3"]
let item = myArray[safe: 1] // item is String?
let strItem = myStringArray[safe: 99] // strItem is String?
How to extend protocol Optional, where Wrapped item is Array of Equatable generic elements?
Cristik provided a good solution. An alternative is to write an extension to an optional collection of equatable elements:
extension Optional where Wrapped: Collection, Wrapped.Element: Equatable {
func foo() { }
}
This would be applicable to arrays, array slices, and other collections.
Depending on what the extension does, you may want to use a combination of Collection
, MutableCollection
, BidirectionalCollection
, RandomAccessCollection
.
Extension optional Array with Optional Element. Is it even possible?
From my understanding, it should work as you did, but one never knows what happens in the swift compiler world (and especially it's error messages).
Anyway, you can circumvent digging deeper into Wrapped.Element.Wrapped
by specifyig the Wrapped.Element
more precisely to be an Optional<FooProtocol>
:
protocol FooProtocol {}
class Foo : FooProtocol {}
extension Optional where
Wrapped: Collection, //OK
Wrapped.Element == Optional<FooProtocol> // still good
{
var unfied: Wrapped.Element // Should be 'Foo' if self is '[Foo?]?' {
{
return 1 == 0 ? nil : Foo()
}
}
Extend an Array of Optional Equatables?
As mentioned in the comments you can't do:
extension Array where Element == Optional<Equatable>
But you can create a generic function in the Array
extension:
extension Array {
func foo<T: Equatable>() where Element == Optional<T> {
...
}
}
Function ArrayOptionalT - OptionalArrayT
Try this:
protocol OptionalType {
typealias W
var optional: W? { get }
}
extension Optional: OptionalType {
typealias W = Wrapped
var optional: W? { return self }
}
extension Array where Element: OptionalType {
func unwrap() -> [Element.W]? {
return reduce(Optional<[Element.W]>([])) { acc, e in
acc.flatMap { a in e.optional.map { a + [$0] } }
}
}
}
And then,
let a: [Int?] = [1, 2, 3]
let b: [Int?] = [1, nil, 3]
a.unwrap() // ==> [1, 2, 3]
b.unwrap() // ==> nil
Is there a way to restrict an Array extension to arrays whose elements are NOT optionals?
This turned out to be an XY problem. The reason why you wanted to do this seems to just be that you cannot distinguish a nil returned by your subscript, and an actual nil in the array.
Well, you can. When you use the subscript on an array of optionals, it would return a double optional. e.g. for [String?]
, it would return String??
.
Here's an example of determining all 3 cases with a switch
. You can use if case
if you just want to check one of them.
switch array[safe: 1] {
case .none: // subscript returned nil
break
case .some(nil): // subscript returned non-nil, but that index in the array contained nil
break
case .some(let x): // subscript returned non-nil, and that index contained x
break
}
So there is really no need to restrict your subscript to non-Optional
arrays. Swift is not designed to allow you to do that anyway.
Just for a bit of fun though, here's how you can abuse Swift's features to make a warning:
extension Array {
subscript<T>(safe index: Int) -> Element? where Element == T {
return indices ~= index ? self[index] : nil
}
@available(swift, deprecated: 1, message: "Do not use this on arrays of optionals!")
subscript<T>(safe index: Int) -> Element? where Element == T? {
return indices ~= index ? self[index] : nil
}
}
I added an extra subscript
that only works on arrays of optionals, but it is marked deprecated since Swift 1 (lol). I added an extra type parameter to the other overload too, so that overload resolution would consider them equally. Otherwise it would always prefer the one with fewer type parameters - we want it to decide based on the generic constraints instead.
Now when you do array[safe: 1]
, overload resolution chooses the one marked deprecated, and produces a warning.
How to create an extension on Swift Array to replace nil with a value?
The use of compactMap
is incorrect here. compactMap
turns a [T]
to another [U]
- it is the mapping function that is allowed to return an optional ((T) -> U?
), and it removes any element for which this function returns nil. This property can be used to remove nil
s from a [T?]
and get a [T]
by passing it { $0 }
, but that's not what you are trying to do with the [T?]
in this case.
What you want here is to turn a [T?]
to [T]
, and you have a one-to-one mapping, which can be done with a map
like this:
extension Sequence {
func replacingNil<T>(with element: T) -> [T] where Element == T? {
self.map { $0 ?? element }
}
}
Swift: Extension on [SomeTypeT?] to produce [T?] possible?
I don't know if there is a simpler solution now, but you can use the same “trick” as in How can I write a function that will unwrap a generic property in swift assuming it is an optional type? and Creating an extension to filter nils from an Array in Swift, the idea goes back to this Apple Forum Thread.
First define a protocol to which all optionals conform:
protocol OptionalType {
associatedtype Wrapped
var asOptional: Wrapped? { get }
}
extension Optional : OptionalType {
var asOptional: Wrapped? {
return self
}
}
Now the desired extension can be defined as
extension Collection where Element: OptionalType, Element.Wrapped: SomeTypeProtocol {
var values: [Element.Wrapped.NumberType?] {
return self.map( { $0.asOptional?.value })
}
}
and that works as expected:
let arr = [SomeType(value: 123), nil, SomeType(value: 456)]
let v = arr.values
print(v) // [Optional(123), Optional(456)]
print(type(of: v)) // Array<Optional<Int>>
Related Topics
Swift Xcode 7 Beta 5 Type Cannot Refer to Itself as a Requirement
Saving And/Or Querying User Display Names in Firebase Using Caseinsensitive
How to Reconstruct Grayscale Image from Intensity Values
Why Does a Function Have Long-Term Write Access to All of Its In-Out Parameters
Swift: Forward Keystrokes to a Different Process
Drawing at Cocoa with Swift Creates an Error
Error Domain=Nsosstatuserrordomain Code=-12780 \"(Null)\"
Working with Nested Async Firebase Calls Swiftui
How Does Swift Disambiguate Type Arguments in Expression Contexts
Swift: Mkannotation Long Title Text
Optional Protocol Requirements, I Can't Get It to Work
Decoding Different Type with and Without Array
Uiview.Animatewithduration Not Animating