我(与网络上的许多其他人一样)希望在Int
数学中使用CGFloat
变量和文字,因为可读性和&到目前为止,易于开发超过了可能的精度损失。当您在整个应用程序中使用手动布局而不是使用故事板时,这一点最为明显。
因此,以下内容应该无需任何手动CGFloat
强制转换:
let a = CGFloat(1)
let b = Int(2)
let c = a / b // Cannot invoke / with an arguments list of type (CGFloat, Int)
let d = b / a // Cannot invoke / with an arguments list of type (Int, CGFloat)
let e = a / 2 // => CGFloat(0.5)
let f = 2 / a // => CGFloat(2.0)
let g = 2 / b // => Int(1)
let h = b / 2 // => Int(1)
let i = 2 / 2 // => Int(1)
let j: CGFloat = a / b // Cannot invoke / with an arguments list of type (CGFloat, Int)
let k: CGFloat = b / a // Cannot invoke / with an arguments list of type (Int, CGFloat)
let l: CGFloat = a / 2 // => CGFloat(0.5)
let m: CGFloat = 2 / a // => CGFloat(2.0)
let n: CGFloat = 2 / b // Cannot invoke / with an arguments list of type (IntegerLiteralConvertible, Int)
let o: CGFloat = b / 2 // Cannot invoke / with an arguments list of type (Int, IntegerLiteralConvertible)
let p: CGFloat = 2 / 2 // => CGFloat(1.0)
由于我们无法向Swift类型添加隐式转换,因此我必须添加适当的运算符CGFloat
和Int
。
func / (a: CGFloat, b: Int) -> CGFloat { return a / CGFloat(b) }
func / (a: Int, b: CGFloat) -> CGFloat { return CGFloat(a) / b }
当Swift尝试从整数文字隐式创建CGFloat
值时,这两个运算符变得模糊不清。它不知道要转换的两个操作数中的哪一个(例如case p
)。
let a = CGFloat(1)
let b = Int(2)
let c = a / b // => CGFloat(0.5)
let d = b / a // => CGFloat(2.0)
let e = a / 2 // => CGFloat(0.5)
let f = 2 / a // => CGFloat(2.0)
let g = 2 / b // => Int(1)
let h = b / 2 // => Int(1)
let i = 2 / 2 // => Int(1)
let j: CGFloat = a / b // => CGFloat(0.5)
let k: CGFloat = b / a // => CGFloat(2.0)
let l: CGFloat = a / 2 // => CGFloat(0.5)
let m: CGFloat = 2 / a // => CGFloat(2.0)
let n: CGFloat = 2 / b // => CGFloat(1.0)
let o: CGFloat = b / 2 // => CGFloat(1.0)
let p: CGFloat = 2 / 2 // Ambiguous use of operator /
有没有办法以不模糊的方式声明运算符并且所有测试用例都成功?
答案 0 :(得分:0)
首先, tl; dr:NO 。
问题在于我们要求编译器隐式地做太多。
我将使用常规函数来获得这个答案,因为我希望它清楚这与运算符无关。
因此,我们需要以下4个功能:
func foo(a: Int, b: Int) -> Int {
return 1
}
func foo(a: Int, b: Float) -> Float {
return 2.0
}
func foo(a: Float, b: Int) -> Float {
return 3.0
}
func foo(a: Float, b: Float) -> Float {
return 4.0
}
现在我们处于相同的情况。我将忽略所有有效的方法并专注于这两种情况:
let bar1 = foo(1,2)
let bar2: Float = foo(1,2)
在第一个场景中,我们要求Swift隐含地确定一件事:bar1
应该是什么类型?我们传递给foo
的两个参数是1
,其类型为IntegerLiteralConvertible
,而2
则属于IntegerLiteralConvertible
类型。
因为foo
只有一个覆盖需要两个Int
个参数,所以Swift能够找出bar1
应该是什么类型,而foo(Int,Int)
的类型是Int
覆盖返回,即func foo(a: Int, b: Int) -> Float {
return 5.0
}
。
现在,考虑我们添加以下功能的场景:
let bar1 = foo(1,2)
现在,方案1变得含糊不清:
foo
我们要求Swift在这里隐含地确定两件事:
bar1
bar1
满足该方案的方法不止一种。 Int
是foo(Int,Int)->Int
我们使用bar2
覆盖,或Float
是foo(Int,Int)->Float
,我们使用let bar1: Int = foo(1,2)
覆盖。编译器无法决定。
尽管如此,我们可以使情况变得模棱两可:
foo(Int,Int)->Int
在这种情况下,编译器知道我们想要let bar2: Float = foo(1,2)
覆盖 - 它是唯一满足该方案的方法。或者我们可以这样做:
foo(Int,Int)->Float
在这种情况下,编译器知道我们想要let bar2: Float = foo(1,2)
覆盖 - 再次,这是满足场景的唯一方法。
但是让我们回顾一下我的情景2,这正是你所遇到的问题:
foo(Int,Int)->Float
没有IntegerLiteralConvertible
覆盖(忘记我们添加此覆盖的方案1的所有内容)。但是,类型foo
可以隐式转换为不同类型的数值数据类型(只有文字整数...而不是整数变量)。因此,编译器将尝试查找IntegerLiteralConvertible
覆盖,该覆盖采用Float
可以强制转换为bar2
的参数并返回IntegerLiteralConvertible
,我们已明确标记为Float
类型。
好吧,foo(Int,Float) -> Float
可以强制转换为foo(Float,Int) -> Float
,因此编译器会找到三个函数,这些函数将右参数组合在一起:
foo(Float,Float) -> Float
foo(Int,Int) -> Float
let bar2: Float = foo(1,2)
编译器不知道使用哪个。怎么样?为什么要优先将一个或另一个文字整数强制转换为浮点数?
所以我们得到了模棱两可的问题。
我们可以给编译器另一个覆盖。它与我们在场景2中给出的相同:IntegerLiteralConvertibles
,现在编译器可以使用以下内容:
foo(Int, Int) -> Float
因为在这种情况下,在没有隐式地转换foo(Int,Int)->Float
的情况下,编译器能够找到匹配的函数:foo(Int,Int) -> Int
foo(Int,Int) -> Float
。
所以现在你在想:
好吧,让我添加一下
let bar3 = foo(1,2)
,一切都会有效!
右?
嗯,抱歉让人失望,但考虑到以下两个功能:
foo
我们仍然会遇到歧义问题:
Int
IntegerLiteralConvertible
有两个覆盖bar3
(或bar3
)的覆盖,因为我们没有指定{{1}}的类型,我们要求编译器都会找出适当的覆盖并隐式确定{{1}}的类型,这是不可能的。