This question already has answers here:
How can I concatenate multiple optional strings in swift 3.0?
(5 answers)
Closed 6 years ago.
I'm using Swift 3.0.
I've got the following code:
var double1 : Double! = 1.0
var double2 : Double! = 2.0
var double3 : Double! = 3.0
When I tried to do the calculation like this:
let result = double1-double2-double3
The compiler gave me the error:
binary operator '-' cannot be applied to operands of type 'Double' and 'Double!'
I've found out that double1-double2 will result a Double value, thus cannot do math with Double!
Then, I've tried:
let result = double1! - double2! - double3!
The compiler gave me this error:
ambiguous reference to member '-'
So what's the correct grammar for this?
Add these custom operator overloads to your project:
public func + <T: FloatingPoint>(lhs: T!, rhs: T!) -> T!
{
if let lhs = lhs, let rhs = rhs
{
return lhs + rhs
}
return nil
}
public func - <T: FloatingPoint>(lhs: T!, rhs: T!) -> T!
{
if let lhs = lhs, let rhs = rhs
{
return lhs - rhs
}
return nil
}
public func * <T: FloatingPoint>(lhs: T!, rhs: T!) -> T!
{
if let lhs = lhs, let rhs = rhs
{
return lhs * rhs
}
return nil
}
public func / <T: FloatingPoint>(lhs: T!, rhs: T!) -> T!
{
if let lhs = lhs, let rhs = rhs
{
return lhs / rhs
}
return nil
}
It will allow for what you were attempting:
var double1 : Double! = 1.0
var double2 : Double! = 2.0
var double3 : Double! = 3.0
let result = double1 - double2 - double3 // -4
And, as a bonus, this will work with any arbitrary FloatingPoint type (including Float and Float80).
One possible workaround is:
let result = (double1 - double2) as Double - double3
Or just cast your doubles to non-optionals. You know that you cannot really perform operations on nil values, right?
Ok,I've found one solution. I can use:
let result = Double(double1) - Double(double2) - Double(double3)
But the code looks anti-humanity. Is there a more elegant way to do this?
Define your Doubles as Double:
var double1 : Double = 1.0
var double2 : Double = 2.0
var double3 : Double = 3.0
The type can also be inferred:
var double1 = 1.0
var double2 = 2.0
var double3 = 3.0
Related
I'm trying to create an extension to the ClosedRange type, that would return nil if the second parameter is lower than the first parameter.
I'm thinking to make something that could be used like this: myClosedRange = ClosedRange.safe(4,3)
I've created an extension like this:
extension ClosedRange {
static func safe(_ lhs: Int, _ rhs: Int) -> ClosedRange<Int>? {
guard lhs >= 0, rhs >= lhs else {
return nil
}
return lhs ... rhs
}
}
But when I try to use it like this: let myRange = ClosedRange.safe(4, 3), I'm getting the error: Generic parameter 'Bound' could not be inferred
I don't understand the error and don't know how to fix it? Any suggestion?
Specify the generic type
let myRange = ClosedRange<Int>.safe(4, 3)
or constrain the Range accordingly
extension ClosedRange where Bound : Comparable, Bound : ExpressibleByIntegerLiteral {
static func safe(_ lhs: Bound, _ rhs: Bound) -> ClosedRange<Bound>? {
guard lhs >= 0, rhs >= lhs else {
return nil
}
return lhs ... rhs
}
}
I would like to override the '=' operator for a CGFloat like the follow try :
func = (inout left: CGFloat, right: Float) {
left=CGFloat(right)
}
So I could do the following:
var A:CGFloat=1
var B:Float=2
A=B
Can this be done ? I get the error Explicitly discard the result of the closure by assigning to '_'
That's not possible - as outlined in the documentation:
It is not possible to overload the default assignment operator (=). Only the compound assignment operators can be overloaded. Similarly, the ternary conditional operator (a ? b : c) cannot be overloaded.
If that doesn't convince you, just change the operator to +=:
func +=(left: inout CGFloat, right: Float) {
left += CGFloat(right)
}
and you'll notice that you will no longer get a compilation error.
The reason for the misleading error message is probably because the compiler is interpreting your attempt to overload as an assignment
You can not override assignment but you can use different operators in your case. For example &= operator.
func &= (inout left: CGFloat, right: Float) {
left = CGFloat(right)
}
So you could do the following:
var A: CGFLoat = 1
var B: Float = 2
A &= B
By the way operators &+, &-, &* exist in swift. They represent C-style operation without overflow. More
This is not operator overload approach. But the result may be what you are expecting
// Conform to `ExpressibleByIntegerLiteral` and implement it
extension String: ExpressibleByIntegerLiteral {
public init(integerLiteral value: Int) {
// String has an initializer that takes an Int, we can use that to
// create a string
self = String(value)
}
}
extension Int: ExpressibleByStringLiteral {
public init(stringLiteral value: String) {
self = Int(value) ?? 0
}
}
// No error, s2 is the string "4"
let s1: Int = "1"
let s2: String = 2
print(s1)
print(s2)
print(s1 + 2)
I have two optional numbers that I add. Right now it looks like this:
if let a = optionalA {
if let b = optionalB {
return a + b
}
}
return nil
For methods, there's the more convenient optional chaining syntax, like optionalA.?method syntax. Is there an equivalent for arithmetic operators that would return nil if either side was nil?
It's possible to create an operator +? that does just this like this:
infix func +?(a: Int?, b: Int?) -> Int? {
if aa = a {
if bb = b {
return aa + bb
}
}
return nil
}
but I'm wondering if there's another, built-in way to do that.
I dont think there is built in way. But you can make your own operator function:
func +(lhs: Int?, rhs: Int?) -> Int? {
if let a = lhs {
if let b = rhs {
return a + b
}
}
return nil
}
var a: Int? = 1
var b: Int? = 2
var c = a + b
Here's the custom operator approach updated for Swift 3:
infix operator +?
func +?(a: Int?, b: Int?) -> Int? {
if let aa = a, let bb = b {
return aa + bb
}
return nil
}
I declare the following:
var x:Int?
var y:Int?
and I'd like a third variable z that contains the sum of x and y. Presumably, as x & y are optionals, z must also be an optional:
var z:Int? = x + y
but this gives a complier error "value of optional type 'Int?' not unwrapped; did you mean to use '!' or '?'"
If I unwrap x & y:
var z:Int? = x! + y!
I get a run-time error as x & y are nil, so can't be unwrapped.
I can achieve the desired result as follows:
var z:Int?
if let x1 = x {
if let y1 = y {
z = x1+y1
}
}
but this seems a bit verbose for adding together 2 integers! Is there a better way of achieving this?
Here is my take, I think it's cleaner:
let none:Int? = nil
let some:Int? = 2
func + (left: Int?, right:Int?) -> Int? {
return left != nil ? right != nil ? left! + right! : left : right
}
println(none + none)
println(none + some)
println(some + none)
println(some + some)
println(2 + 2)
With results of:
nil
Optional(2)
Optional(2)
Optional(4)
4
The best I can think of is:
if x && y {
z = x! + y!;
}
Since they are all Optionals... there's really no way to avoid:
checking that they aren't nil
Unwrapping them before you add them.
Best solution IMO:
z = x.map { x in y.map { $0 + x } }
Did you know the map operator on Optional<T>? It is very nice.
Documentation says:
If self == nil, returns nil. Otherwise, returns f(self!).
It depends exactly what you're trying to achieve, but you could do it with an optional tuple:
var xy: (Int, Int)?
var z: Int
if let (x1, y1) = xy {
z = x1 + y1 // Not executed
}
xy = (3, 4)
if let (x1, y1) = xy {
z = x1 + y1 // 7
}
Update
As #Jack Wu points out, this changes the semantics. If you were willing to be a bit more verbose, you could however do it as follows:
func optIntAdd(x: Int?, y: Int?) -> Int? {
if let x1 = x {
if let y1 = y {
return x1 + y1
}
}
return nil
}
operator infix +! { }
#infix func +! (x: Int?, y: Int?) -> Int?{
return optIntAdd(x, y)
}
var x: Int?
var y: Int?
var z: Int?
z = x +! y // nil
x = 1
z = x +! y // nil
y = 2
z = x +! y // 3
Not sure "+!" is a useful choice of name for the operator, but it would't let me choose "+?".
Someday, we'll have variadic generics. Until then, you need a pair of overloads for all arities.
var z = Optional(x, y).map(+)
public extension Optional {
/// Exchange two optionals for a single optional tuple.
/// - Returns: `nil` if either tuple element is `nil`.
init<Wrapped0, Wrapped1>(_ optional0: Wrapped0?, _ optional1: Wrapped1?)
where Wrapped == (Wrapped0, Wrapped1) {
self = .init((optional0, optional1))
}
/// Exchange two optionals for a single optional tuple.
/// - Returns: `nil` if either tuple element is `nil`.
init<Wrapped0, Wrapped1>(_ optionals: (Wrapped0?, Wrapped1?))
where Wrapped == (Wrapped0, Wrapped1) {
switch optionals {
case let (wrapped0?, wrapped1?):
self = (wrapped0, wrapped1)
default:
self = nil
}
}
}
z = (x ?? 0) + (y ?? 0)
* Worked on Xcode 9 *
Swift 5.5 Sum any optional values
infix operator +?: AdditionPrecedence
public func +? <T: AdditiveArithmetic>(lhs: T?, rhs: T?) -> T {
if let lhs = lhs, let rhs = rhs {
return lhs + rhs
} else if let lhs = lhs {
return lhs
} else if let rhs = rhs {
return rhs
} else {
return .zero
}
}
given this code
extension Array {
func filter(includeElement: (T) -> Bool) -> T[] {
var ret = T[]()
for e in self {
if includeElement(e) {
ret += e
}
}
return ret
}
}
var a = [1,2]
var b = a.filter() {i in print(i); return true}
it can't compile with error message
error: ambiguous use of 'filter'
var b = a.filter() {i in print(i); return true}
^
Swift.Array<T>:84:8: note: found this candidate
func filter(includeElement: (T) -> Bool) -> Array<T>
^
<REPL>:30:10: note: found this candidate
func filter(includeElement: (T) -> Bool) -> T[] {
^
so looks like I am allowed to create extension method with duplicated method and signature, but I somehow need a special way to call it
BTW, default Array.filter is broken, it calls the closure twice for each element and crashes REPL or give your rubbish result in playground if the result is inconsistent
xiliangchen-imac:~ xiliangchen$ xcrun swift
Welcome to Swift! Type :help for assistance.
1> let arr = [1,2,3,4,5]
arr: Int[] = size=5 {
[0] = 1
[1] = 2
[2] = 3
[3] = 4
[4] = 5
}
2> var i = 0
i: Int = 0
3> let arr2 = arr.filter() {
4. println($0)
5. return i++ < 5
6. }
Segmentation fault: 11
There is no problem with defining ambiguous methods, I think. The problem arises when you import 2 ambiguos methods from different modules. Unfortunately, there is no way how to exclude the Array.filter from being imported.
I did some tests and it appears to me the behavior for ambigious definitions is not well defined, for example:
extension NSString {
func hasPrefix(aString: String!) -> Bool {
return false
}
}
let string: NSString = "test"
var hasPrefix = string.hasPrefix("t")
println("Has prefix: \(hasPrefix)") //prints "true"
var method = string.hasPrefix
hasPrefix = method("t")
println("Has prefix: \(hasPrefix)") //prints "false"
The behavior could be different for obj-c classes...
For functions, it appears the definition from current module is preferred:
func NSStringFromCGPoint(point: CGPoint) -> String! {
return "My method"
}
var point = CGPoint(x: 10.0, y: 10.0)
println("Point: \(NSStringFromCGPoint(point))") //Prints "My method"
println("Point: \(UIKit.NSStringFromCGPoint(point))") //Prints "{10, 10}"