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
}
})
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
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
I'm kinda new to Swift and I was wondering how do I make a function accept an array that contains all kinds of variables types. I want the function to just accept 'Array' without a specific type but it throws an error. Here's my code:
func length(arry arry: Array)
{
}
I know I have to put a <> after the Array but I need the function to universally accept all arrays.
EDITED:
Whenever I add an extension I get these ridiculous errors. My code is:
//: Playground - noun: a place where people can play
import UIKit
extension Array {
var length: Int {
return self.count
}
}
var arrY = ["Hello", 0]
for(var i = 0; i < length(arry: arrY); i++)
{
print(arrY[i]);
}
arrY.append(28);
var h = arrY.removeAtIndex(0);
print(h);
I get errors saying:
1 On line ten Extensions may not contain stored properties
2 On line eleven Expected Declaration
3 On line eighteen Expected Declaration
Thanks,
Jack
If you want, you can write a generic function:
func length<T>(arry arry: Array<T>)
{
}
In Swift, Apple introduced the concept of Generics which you can also now find it on Xcode 7 and Objective-C. This feature allows you to define the type of each element in the Array or the collection class that you're using. You can define a generic class or a generic method like the sample given. This feature gives you the ability of writing your code in a way that it can work safely with different types, while taking advantage of being type-safe. For example, in the sample that I gave, it's saying that length is a generic method which takes an Array of type T as input. Writing a method like this, allows you to write one method which is capable of accepting arrays of different types. For example, following sample code, is showing that you can use the same method for both array of Int and array of Double:
var arr = [13, 23, 32]
var arr2 = [12.3, 23.5, 13.14, 2.75]
var arr3 = ["foo", "boo"]
length(arr)
length(arr)
length(arr)
For more information on Generics you can check online documents at this Link, and/or watch Swift introduction videos for WWDC 2014, and/or reading generic section of The Swift Programming Language
Using a generic function is the better answer. But you could also use [Any] as a parameter for this function.
func length(array: [Any])->Int{
return array.count
}
If you're used to .length then make an extension to Array with a length property:
extension Array {
var length: Int {
return self.count
}
}
Then you can call it on arrays like you're used to:
["a", "b"].length // 2
[0, 1].length // 2
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.
This question already has answers here:
Passing lists from one function to another in Swift
(2 answers)
Passing an array to a function with variable number of args in Swift
(7 answers)
Closed 8 years ago.
In "The Swift Programming Language", Functions and Closures, there is a sample code to calculate the total as below:
func sumOf(numbers: Int...) -> Int {
var sum = 0
for number in numbers {
sum += number
}
return sum
}
As part of the following experiment, I tried the following function to calculate the average
func averageOf(numbers : Int...) -> Int {
var argument:Array = numbers
var average = sumOf(argument) / numbers.count
return average
}
However, I get the following error
[Int] is not convertible to Int
I have also tried the following line with no success
var average = sumOf(numbers) / numbers.count
Any idea whats going on underneath? Why is sumOf parameter is treating it as Int instead of an array when the book clearly states that
“Functions can also take a variable number of arguments, collecting
them into an array.”
It seems to me you function is ok if you try to call it properly.
sumOf(25,23,43,23)
But if you would like to call array use this code :
import UIKit
var someInts = [Int]()
someInts.append(8)
someInts.append(6)
someInts.append(6)
someInts.append(3)
someInts.append(5)
func sumOf(numbers: [Int]) -> Int {
var sum = 0
for number in numbers {
sum += number
}
return sum
}
sumOf(someInts)
The main problem that in function you declare parameter not as array but like undefined amount of the integers
Just change definition of method To
func sumOf(numbers: [Int]) -> Int
Instead Of
func sumOf(numbers: Int...) -> Int
Because you are passing array as an argument to func sumOf function, which is not expected as its define.