I am trying to concatenate multiple strings in swift 3:
var a:String? = "a"
var b:String? = "b"
var c:String? = "c"
var d:String? = a! + b! + c!
When compiling I get the following error:
error: cannot convert value of type 'String' to specified type 'String?'
var d:String? = a! + b! + c!
~~~~~~~~^~~~
This used to work in swift 2. I am not sure why it doesn't work anymore.
Bug report filed by OP:
SR-1122: Failure to typecheck chain of binary operators on force-unwrapped values
Which has been resolved (fix commited to master Jan 3 2017), and should hence no longer be an issue in upcoming Swift 3.1.
This seems to be a bug (not present in Swift 2.2, only 3.0) associated with the case of:
Using the forced unwrapping operator (!) for at least 3 terms in an expression (tested using at least 2 basic operators, e.g. + or -).
For some reason, given the above, Swift messes up type inference of the expression (specifically, for the x! terms themselves, in the expression).
For all the examples below, let:
let a: String? = "a"
let b: String? = "b"
let c: String? = "c"
Bug present:
// example 1
a! + b! + c!
/* error: ambiguous reference to member '+' */
// example 2
var d: String = a! + b! + c!
/* error: ambiguous reference to member '+' */
// example 3
var d: String? = a! + b! + c!
/* error: cannot convert value of type 'String'
to specified type 'String?' */
// example 4
var d: String?
d = a! + b! + c!
/* error: cannot assign value of type 'String'
to specified type 'String?' */
// example 5 (not just for type String and '+' operator)
let a: Int? = 1
let b: Int? = 2
let c: Int? = 3
var d: Int? = a! + b! + c!
/* error: cannot convert value of type 'Int'
to specified type 'Int?' */
var e: Int? = a! - b! - c! // same error
Bug not present:
/* example 1 */
var d: String? = a! + b!
/* example 2 */
let aa = a!
let bb = b!
let cc = c!
var d: String? = aa + bb + cc
var e: String = aa + bb + cc
/* example 3 */
var d: String? = String(a!) + String(b!) + String(c!)
However as this is Swift 3.0-dev, I'm uncertain if this is really a "bug", as well as what's the policy w.r.t. reporting "bugs" in a not-yet-production version of code, but possibly you should file radar for this, just in case.
As for answering your question as how to circumvent this issue:
use e.g. intermediate variables as in Bug not present: Example 2 above,
or explicitly tell Swift all terms in the 3-term expression are strings, as in Bug not present: Example 3 above,
or, better yet, use safe unwrapping of your optional, e.g. using optional binding:
var d: String? = nil
if let a = a, b = b, c = c {
d = a + b + c
} /* if any of a, b or c are 'nil', d will remain as 'nil';
otherwise, the concenation of their unwrapped values */
Swift 3
let q: String? = "Hello"
let w: String? = "World"
let r: String? = "!"
var array = [q, w, r]
print(array.flatMap { $0 }.reduce("", {$0 + $1}))
// HelloWorld!
let q: String? = "Hello"
let w: String? = nil
let r: String? = "!"
var array = [q, w, r]
print(array.flatMap { $0 }.reduce("", {$0 + $1}))
// Hello!
func getSingleValue(_ value: String?..., seperator: String = " ") -> String? {
return value.reduce("") {
($0) + seperator + ($1 ?? "")
}.trimmingCharacters(in: CharacterSet(charactersIn: seperator) )
}
let val: String? = "nil"
val.flatMap({(str: String) -> String? in
return str + "value"
})
var a:String? = "a"
var b:String? = "b"
var c:String? = "c"
var d:String? = ""
let arr = [a,b,c]
arr.compactMap { $0 }.joined(separator: " ")
compactMap be used to filter out nil values from flattened arrays
Related
This question already has answers here:
What does "Fatal error: Unexpectedly found nil while unwrapping an Optional value" mean?
(16 answers)
Closed 1 year ago.
Good Evening, Hi guys i am new with swift, so i try to make a simple calculator by converting an infix notation to a postfix notation. Basically the code gonna works like this,
All numbers are pushed to the output when they are read.
At the end of reading the expression, pop all operators off the stack and onto the output.
So i try to compile the code and it says that Fatal error: Unexpectedly found nil while unwrapping an Optional value:
can someone help with with this
thank you so much :)
Fatal error: Unexpectedly found nil while unwrapping an Optional value:
import UIKit
var tokens: [String] = ["4 + 4 + 2"]
func precedence(op: String) -> Int{
if(op == "+" || op == "-"){
return 1
}
if(op == "*" || op == "/" || op == "%"){
return 2
}
return 0
}
func applyOp(a: Int, b: Int, op: String) -> Int{
switch op{
case "+":
return a + b
case "-":
return a - b
case "*":
return a * b
case "/":
return a / b
case "%":
return a % b
default:
return 0
}
return 0
}
func evaluate(tokens: [String]) -> Int{
var i: Int! = 0
var values: [Int] = []
var ops : [String] = []
while i < tokens.count{
if(tokens[i] >= "0" && tokens[i] <= "9"){
var val : Int = 0
while i < tokens.count && tokens[i] >= "0" && tokens[i] <= "9"{
val = (val * 10) + Int(tokens[i])!
i = i + 1
}
values.append(val)
i = i - 1
}
else{
while ops.count != 0 && precedence(op: ops[-1]) >= precedence(op: tokens[i]){
let val2 : Int! = values.popLast()
let val1 : Int! = values.popLast()
let op : String! = ops.popLast()
values.append(applyOp(a: val1, b: val2, op: op))
}
}
i = i + 1
}
while ops.count != 0{
let val2 : Int! = values.popLast()
let val1 : Int! = values.popLast()
let op : String! = ops.popLast()
values.append(applyOp(a: val1, b: val2, op: op))
}
return Int(values[-1])
}
print(evaluate(tokens: tokens))
you try to force cast a String to Int
val = (val * 10) + Int(tokens[i])!
tokens is an array of String, so if you force cast to Int you will get a nil
I want to pass the value as reference.
var a = "*"
var b = ""
func hello(c: inout String){
b = c
a = "**"
print(b)
print(c)
}
hello(c: &a)
The output for the above is
B: *
C: **
I want to change the value of B as well as in, I want to pass the reference to B not the value
I want the output to be
B: **
C: **
Any help would be appreciated. Thanks in advance
Something that you can do is this
var b = ""
var a = "*"{
didSet{
b = a
}
}
and when the value of a changes the b will have the value of a
I have an input (String): "1 * 2 + 34 - 5" and I want to split it into array and then convert "convertible" elements into integers. My code looks like this:
let arr: [Any] = readLine()!.split(separator: " ").map {Int($0) != nil ? Int($0) : $0}
Splitting is not a problem but I don't know why mapping doesn't work as it should. I get error:
error: cannot invoke initializer for type 'Int' with an argument list of type '((AnySequence<String.Element>))'
note: overloads for 'Int' exist with these partially matching parameter lists: (Float), (Double), (Float80), (Int64), (Word), (NSNumber), (CGFloat)
I try to do the same in another way, with initializing new array:
let arr = readLine()!.split(separator: " ")
let newArray: [Any] = arr.map {Int($0) != nil ? Int($0) : $0}
but it also throws me an error:
error: 'map' produces '[T]', not the expected contextual result type '[Any]'
It is suprise for me that when I'm trying to do the same with for loop it works perfectly:
let arr = readLine()!.split(separator: " ")
var newArray = [Any]()
for x in arr
{
if Int(x) != nil {newArray.append(Int(x)!)}
else {newArray.append(x)}
}
print(newArray)
output: [1, "*", 2, "+", 34, "-", 5]
Can someone explain to me what is going on here? I mean if all 3 codes do the same thing so why only "for loop" works fine?
You'll need to specify that the return type of your map block is Any rather than the type which is being inferred by the compiler (Int), e.g.
let fullString = "1 * 2 + 34 - 5"
let elements = fullString
.components(separatedBy: " ")
.map { Int($0) ?? $0 as Any}
Is there a good reason why this fails:
class Test<T: Hashable> {}
var d: Test<AnyHashable>? = nil
let t = Test<String>()
d = t // Cannot assign value of type 'Test<String>' to type 'Test<AnyHashable>?'
while this obviously works ?
var d: AnyHashable? = nil
let t = "123"
d = t // Works fine
After reading of the article about swift compiling time. I am interested in why usage of more than 2 sequence coalescing operator increase compilation time significantly.
Example:
Compilation time 3.65 sec.
func fn() -> Int {
let a: Int? = nil
let b: Int? = nil
let c: Int? = nil
return 999 + (a ?? 0) + (b ?? 0) + (c ?? 0)
}
Compilation time 0.09 sec.
func fn() -> Int {
let a: Int? = nil
let b: Int? = nil
let c: Int? = nil
var res: Int = 999
if let a = a {
res += a
}
if let b = b {
res += b
}
if let c = c {
res += c
}
return res
}
I'm almost certain that this has to do with type inference. When interpreting all of those + and ?? operators the compiler is doing a lot of work behind the scenes to infer the types of those arguments. There are around thirty overloads for the + operator alone and when you chain several of them together you are making the compiler's job much more complicated than you might think.