I'm trying to learn about swift and closures.
I'm stuck on this example.
numbers.map({
(number: Int) -> Int in
let result = 3 * number
return result
})
What is (number: Int) -> Int? Is it a function? Where is it defined?
https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/GuidedTour.html#//apple_ref/doc/uid/TP40014097-CH2-ID1
What does the keyword "in" do? The docs say to use "to separate the arguments and return type from the body". I'm not sure I understand this. Why isn't "in" used to separate "let result = 3 * number" from "return result".
A closure is just a function with the parameters moved inside the brackets, with the keyword in to separate the parameters from the function body. The two following examples define equivalent functions:
func myFunc(number: Int) -> Int {
let result = 3 * number
return result
}
let myClosure = { (number: Int) -> Int in
let result = 3 * number
return result
}
You can actually call them both in exactly the same way:
let x = myFunc(2) // x == 6
let y = myClosure(2) // y == 6
Notice how the second example is exactly the same as the first, only in the first example, the parameters (number: Int) -> Int are outside the brackets, and in the second example the parameters are inside the brackets, followed by the keyword in.
map works by taking an array (numbers, in your example) and creating a new array that is the result of applying the closure function to each element in numbers. So if numbers is [1, 2, 3], the example above will start with 1. It will apply the closure function which will produce a 3 (cuz all it does is multiply the element from the first array by 3). It does that for each element in numbers, until it has produced a new array, [3, 6, 9].
If you wanted to, you could call map using the names of either the above function or the above closure, or by writing it out explicitly inside of map. All of the below examples are totally equivalent:
let numbers = [1, 2, 3]
// Example 1
let times3 = numbers.map(myFunc) // times3 == [3, 6, 9]
// Example 2
let timesThree = numbers.map(myClosure) // timesThree == [3, 6, 9]
// Example 3
let xThree = numbers.map({ (number: Int) -> Int in
let result = 3 * number
return result // xThree == [3, 6, 9]
})
Note that Example 3 is the same as Example 2, only in Example 3 the closure is spelled out explicitly inside of map, whereas in Example 2 the closure has been assigned to a constant called myClosure, and the constant has been supplied to map.
Hope this helps - closures are fun, but confusing.
The function you're calling takes a closure as its parameter:
numbers.map({...})
The closure provided to the function is expected to receive a parameter when it is executed by the function you called. This parameter is defined in your closure:
(number: Int) -> Int in
You may now use the parameter in the contents of the closure
let result = 3 * number
return result
Closures are self-contained blocks of functionality that can be passed around and used in your code.
Syntax:
{(parameterName: ParameterType) -> returnType in
//Statements
}
Practical Scenario: When user want to apply filter and want to select values which is more than 300(in this case) we can use closures to achive this.
var elements: [Int] = [Int]() //Declaring Empty array
elements = [1001, 999, 555, 786, 988, 322, 433, 128, 233, 222, 201, 276, 133]
var filteredElements = elements.map({(num: Int) -> Int? in
return num > 300 ? num : nil
})
output:
[Optional(1001), Optional(999), Optional(555), Optional(786), Optional(988), Optional(322), Optional(433), nil, nil, nil, nil, nil, nil]
From Below code you can clearly see we are passing closure to elements.map() function.
Closure:
{(num: Int) -> Int? in
return num > 300 ? num : nil
}
(num:Int) is parameter.
Int? is we are going to return Optional Integer Type.
After in we can write your logic.
You can read more about closure here.
Related
I want to save a function that takes two parameters as a function that only takes one parameter. I know I learned this with functional programming but I can't remember the methodology name or how to implement it.
Example: a methods like this:
func add (a: Int, b: Int) {
return a + b
}
And you can manipulate and save a new method that let’s say only increments a by 1:
let increment = add(b:1)
print(increment(a: 4))
// prints 5
Can you do this in swift?
It seems you're looking for function currying. This was a part of swift in earlier versions but was removed because it added too much complexity inside the compiler. (Like seen here: https://github.com/apple/swift-evolution/blob/master/proposals/0002-remove-currying.md)
I guess the closest you can get to a curried function is if you do something like this:
func add(_ x: Int) -> (Int) -> Int {
return { y in
y + x
}
}
With this you can say:
let add2 = add(2)
print(add2(3)) // prints 5
You are looking for Default Parameter Values
You can assign default values to the parameters. When calling this function if you pass the value to the parameters that passed value will be used else the default value will be used. To use the default value you can avoid the parameter in the function calling
func add(a: Int = 1, b: Int = 1) -> Int {
return a + b
}
print(add(a: 5, b: 5))//prints 10
print(add(a: 4))//prints 5
print(add(b: 4))//prints 5
print(add())//prints 2
So in the "Swift Tour" (https://docs.swift.org/swift-book/GuidedTour/GuidedTour.html) is a part about closures.
The code in their example is the following:
numbers.map({ (number: Int) -> Int in
let result = 3 * number
return result
})
But when tryin to run this, you get following error: " error: use of unresolved identifier 'numbers' "
So my questions are:
What are closures/ Could anyone explain the usage of these?
What is wrong with the example (it´s the official code example of the Swift documentation..)
The array numbers is declared on line 12 of the previous code block. Each code block shown in that chapter builds on the one before. You can download the code as a playground
The functioning code block would be:
var numbers = [20, 19, 7, 12]
numbers.map({ (number: Int) -> Int in
let result = 3 * number
return result
})
Closures are described in more detail in their own chapter but in summary:
Closures are self-contained blocks of functionality that can be passed around and used in your code. Closures in Swift are similar to blocks in C and Objective-C and to lambdas in other programming languages.
In the case of the map function, the code in the closure operates on each element of the array in turn. It accepts the array element as input and returns an element for the output array.
You can return 0 for odd numbers using the modulo function
let evens = numbers.map({ (number: Int) -> Int in
if number % 2 == 0 {
return number
} else {
return 0
}
})
var a = [1,2,3]
let ptr1 = UnsafeMutablePointer<Int>(&a[0]) //works fine
let index = 0
let ptr2 = UnsafeMutablePointer<Int>(&a[index]) //compiler throws error
error: cannot invoke initializer for type UnsafeMutablePointer<Int> with an argument list of type (inout Int)
Why the latter one doesn't compile? Is there anything I am missing here?
I wanted to do like a below snippet.
class Holder {
var numbers: [Int] = [1,2,3,4]
var modifier: Modifier
init(index: Int) {
self.modifier = Modifier(UnsafeMutablePointer(&self.numbers) + index)
}
}
class Modifer {
var ptr: UnsafeMutablePointer<Int>
init(_ ptr: UnsafeMutablePointer<Int>) {
self.ptr = ptr
}
func change(to: Int) {
self.ptr.pointee = to
// expected the change to be reflected in numbers array
// but as Rob Napier said it became invalid and throws EXC_BAD_ACCESS
}
}
How can I achieve the above expected result?
Note that neither of these is a valid way to create an UnsafeMutablePointer. Swift is free to deallocate a immediately after the last time it is referenced, so by the time you use these pointers, they may be invalid. The tool you want is a.withUnsafeMutableBufferPointer.
That said, the correct syntax here is:
let ptr2 = UnsafeMutablePointer(&a) + index
Looking at your updated code, there's no way for this to make sense on Array. I think you're assuming that Arrays are reference types. They're value types. There's no way to change a piece of numbers. Any change to it replaces the entire array with a completely different array. Swift has some clever copy-on-write tricks to make this efficient, and in practice it may not actually replace the entire array, but you should program as though it did. You should consider the following line:
array[1] = 2
to be equivalent to:
array = <a new array that is identical, but element 1 has been replaced by 2>
This means that pointers into Array are meaningless outside of very controlled situations (such as inside a withUnsafeMutableBufferPointer block).
What you want is something more like this:
class Holder {
var numbers: [Int] = [1,2,3,4]
private(set) var modifier: ((Int) -> ())! // ! is an artifact of capturing self in init
init(index: Int) {
self.modifier = { [weak self] in self?.numbers[index] = $0 }
}
}
let holder = Holder(index: 2)
holder.numbers // [1, 2, 3, 4]
holder.modifier(0)
holder.numbers // [1, 2, 0, 4]
In The Swift Programming Language, it says:
Functions can also take a variable number of arguments, collecting them into an array.
func sumOf(numbers: Int...) -> Int {
...
}
When I call such a function with a comma-separated list of numbers (`sumOf(1, 2, 3, 4), they are made available as an array inside the function.
Question: what if I already have an array of numbers that I want to pass to this function?
let numbers = [1, 2, 3, 4]
sumOf(numbers)
This fails with a compiler error, “Could not find an overload for '__conversion' that accepts the supplied arguments”. Is there a way to turn an existing array into a list of elements that I can pass to a variadic function?
Splatting is not in the language yet, as confirmed by the devs. Workaround for now is to use an overload or wait if you cannot add overloads.
Here's a work around that I found. I know it's not exactly what you want, but it seems to be working.
Step 1: Declare the function you'd like with an array instead of variadic arguments:
func sumOf(numbers: [Int]) -> Int {
var total = 0
for i in numbers {
total += i
}
return total
}
Step 2: Call this from within your variadic function:
func sumOf(numbers: Int...) -> Int {
return sumOf(numbers)
}
Step 3: Call Either Way:
var variadicSum = sumOf(1, 2, 3, 4, 5)
var arraySum = sumOf([1, 2, 3, 4, 5])
It seems strange, but it is working in my tests. Let me know if this causes unforeseen problems for anyone. Swift seems to be able to separate the difference between the two calls with the same function name.
Also, with this method if Apple updates the language as #manojid's answer suggests, you'll only need to update these functions. Otherwise, you'll have to go through and do a lot of renaming.
You can cast the function:
typealias Function = [Int] -> Int
let sumOfArray = unsafeBitCast(sumOf, Function.self)
sumOfArray([1, 2, 3])
You can use a helper function as such:
func sumOf (numbers : [Int]) -> Int { return numbers.reduce(0, combine: +) }
func sumOf (numbers : Int...) -> Int { return sumOf (numbers) }
I did this (Wrapper + Identity Mapping):
func addBarButtonItems(types: REWEBarButtonItemType...) {
addBarButtonItems(types: types.map { $0 })
}
func addBarButtonItems(types: [REWEBarButtonItemType]) {
// actual implementation
}
I know this response does not answer your exact question, but I feel its worth noting. I too was starting to play with Swift and immediately ran into a similar question. Manojlds answer is better for your question, I agree, but again, another workaround I came up with. I do happen to like Logan's better too.
In my case I just wanted to pass an array:
func sumOf(numbers: Array<Int>) -> Int {
var sum = 0
for number in numbers {
sum += number
}
return sum
}
var someNums = [8,7,2,9,12]
sumOf(someNums)
sumOf([10, 15, 20])
Just wanted to share, in case anyone else was thinking like me. Most of the time I would prefer pass the array like this, but I don't think the "Swiftly" yet. :)
Swift 5
This is an approach with #dynamicCallable feature that allows to avoid overloading or unsafeBitCast but you should make a specific struct to call:
#dynamicCallable
struct SumOf {
func dynamicallyCall(withArguments args: [Int]) -> Int {
return args.reduce(0, +)
}
}
let sum = SumOf()
// Use a dynamic method call.
sum(1, 2, 3) // 6
// Call the underlying method directly.
sum.dynamicallyCall(withArguments: [1, 2, 3]) // 6
Two faceted question:
var array = [1,2,3,4,5]
contains(array, 0) // false
var array2: NSArray = [1,2,3,4,5]
array2.containsObject(4) // true
Is there any way to search an Array for more than 1 value? ie. Can I write below to search the array for multiple values and return true if any of the values are found? Second part to the question is how can I do that for an NSArray as well?
var array = [1,2,3,4,5]
contains(array, (0,2,3)) // this doesn't work of course but you get the point
You can chain contains together with a second array:
// Swift 1.x
contains(array) { contains([0, 2, 3], $0) }
// Swift 2 (as method)
array.contains{ [0, 2, 3].contains($0) }
// and since Xcode 7 beta 2 you can pass the contains function which is associated to the array ([0, 2, 3])
array.contains([0, 2, 3].contains)
// Xcode 12
array.contains(where: [0, 2, 3].contains)
One option would be to use a Set for the search terms:
var array = [1,2,3,4,5]
let searchTerms: Set = [0,2,3]
!searchTerms.isDisjointWith(array)
(You have to negate the value of isDisjointWith, as it returns false when at least one of the terms is found.)
Note that you could also extend Array to add a shorthand for this:
extension Array where Element: Hashable {
func containsAny(searchTerms: Set<Element>) -> Bool {
return !searchTerms.isDisjointWith(self)
}
}
array.containsAny([0,2,3])
As for the NSArray, you can use the version of contains which takes a block to determine the match:
var array2: NSArray = [1,2,3,4,5]
array2.contains { searchTerms.contains(($0 as! NSNumber).integerValue) }
Explanation of closure syntax (as requested in comments): you can put the closure outside the () of method call if it's the last parameter, and if it's the only parameter you can omit the () altogether. $0 is the default name of the first argument to the closure ($1 would be the second, etc). And return may be omitted if the closure is only one expression. The long equivalent:
array2.contains({ (num) in
return searchTerms.contains((num as! NSNumber).integerValue)
})
Swift 5.7 +
A quick syntax fix to the accepted answer for the latest version of swift:
extension Array where Element: Hashable {
func containsAny(searchTerms: Set<Element>) -> Bool {
return !searchTerms.isDisjoint(with: self)
}
}