不调用伴随对象中声明的隐式转换
Implicit conversion declared in companion object is not called
我正在 Scala implicits 上尝试示例程序。我正在尝试实施“Scala for the Impatient”一书中的一个解决方案。
我已经写成 Fraction class 有两个成员变量 numerator 和 denominator 带有操作重载方法 "*(fraction)",这样我们就可以在 Fraction 对象上调用乘法,例如 fration1 * fraction2 * fraction3.
现在,我尝试实现 intToFraction 和 fractionToInt 隐式方法,这样我们也可以编写类似 2[=23= 的语法]分数13。我尝试在 Fraction class 的伴随对象中实现这些方法。但是这些方法没有被调用。
正如 Scala 文档所建议的那样,Scala 编译器将尝试找出伴随对象中的隐式实现。在这里,我们正在对 Fraction class 的对象执行操作,所以我假设,在 Fraction 中声明的隐式应该被自动调用。我也尝试过显式导入隐式方法,但没有用。
请在下面找到代码片段以供参考。
package com.example.implicits.conversion
object ImplicitConversionTester extends App {
val f1 = Fraction(4,2)
val result = 2 * f1
println(s"${f1 * f1}")
println(s"${result}")
}
class Fraction(val numerator : Int,val denominator : Int) {
def *(fraction : Fraction): Fraction = {
println("##### Call to operator overloading *")
Fraction(this.numerator*fraction.numerator, this.denominator*fraction.denominator)
}
override def toString: String = s"Fraction($numerator,$denominator) ===== ${numerator/denominator}"
}
object Fraction {
def apply(numerator: Int, denominator: Int): Fraction = new Fraction(numerator, denominator)
implicit def intToFraction(num : Int) = {
println("##### intToFraction")
Fraction(num,1)
}
implicit def fractionToInt(fr : Fraction) = {
println("##### fractionToInt")
fr.numerator/fr.denominator
}
}
感谢任何解决此问题的建议!
你是对的,scala 编译器首先在
中查找隐式
- 当时的当前范围
- 然后在伴随范围内
- 在导入范围内
在你的例子中,编译器在主单例对象的范围内寻找隐式 ImplicitConversionTester
并且它不会找到任何东西,因为没有任何隐式可用。如果你导入隐式那么它应该工作 -
object Implicit extends App {
import Fraction._
class Fraction(val numerator : Int,val denominator : Int) {
def * (fraction : Fraction): Fraction = {
println("##### Call to operator overloading *")
Fraction(this.numerator*fraction.numerator, this.denominator*fraction.denominator)
}
}
object Fraction {
def apply(numerator: Int, denominator: Int): Fraction = new Fraction(numerator, denominator)
implicit def intToFraction(num : Int) = {
println("##### intToFraction")
Fraction(num,1)
}
implicit def fractionToInt(fr : Fraction) = {
println("##### fractionToInt")
fr.numerator/fr.denominator
}
}
println(Fraction(1,2) * 2)
}
问题出在没有明确提及 return 类型的隐式方法声明中。我没有在上面的代码片段中提到 return 类型。添加函数 return 类型后,隐式函数工作正常。因此,无需在 ImplicitConversionTester class 中显式导入隐式函数来解决问题。
以下是修正错误的更新分数 class:
class Fraction(val numerator : Int,val denominator : Int) {
val test = 2
def *(fraction : Fraction): Fraction = {
println("##### Call to operator overloading *")
Fraction(this.numerator*fraction.numerator, this.denominator*fraction.denominator)
}
override def toString: String = s"Fraction($numerator,$denominator) ===== ${numerator/denominator}"
}
object Fraction {
def apply(numerator: Int, denominator: Int): Fraction = new Fraction(numerator, denominator)
implicit def intToFraction(num : Int) : Fraction = { // RETURN TYPE FRACTION
println("##### intToFraction")
Fraction(num,1)
}
implicit def fractionToInt(fr : Fraction) : Int = { // ADDED RETURN TYPE INT
println("##### fractionToInt")
fr.numerator/fr.denominator
}
}
在下面分享有关 Scala 编译器如何查找隐式转换的更多详细信息。下图摘自《Scala for the Impatient》一书。
如书中所述,Scala 编译器优先考虑 source 或 target 类型的伴随对象。
这里,什么是source和target类型,取决于表达式的顺序。例如,如果表达式是“2*Fraction(2,4)”,则表达式从左到右求值。整数“2”已经实现了乘法方法 (*)。因此,编译器首先尝试在“Int”类型中找到从“Fraction to Int”的隐式转换。由于“Int”类型没有“Fraction to Int”的任何实现,编译器将查找 Fraction class 的伴生对象,并在其中找到方法“fractionToInt”。在此示例中,目标类型为 Int,源类型为 Fraction。
考虑表达式 "Fraction(2,4)*2" 的示例,这里作为 Fraction class 具有可用于乘法 "*" 的实现,编译器试图找到将 Int 转换为 Fraction 的隐式。所以目标类型是 Fraction,Source 类型是 Int。由于 Int class 中不存在此类隐式 method/class,编译器查找 Fraction 伴随对象并找到“IntToFraction”隐式。
我正在 Scala implicits 上尝试示例程序。我正在尝试实施“Scala for the Impatient”一书中的一个解决方案。
我已经写成 Fraction class 有两个成员变量 numerator 和 denominator 带有操作重载方法 "*(fraction)",这样我们就可以在 Fraction 对象上调用乘法,例如 fration1 * fraction2 * fraction3.
现在,我尝试实现 intToFraction 和 fractionToInt 隐式方法,这样我们也可以编写类似 2[=23= 的语法]分数13。我尝试在 Fraction class 的伴随对象中实现这些方法。但是这些方法没有被调用。
正如 Scala 文档所建议的那样,Scala 编译器将尝试找出伴随对象中的隐式实现。在这里,我们正在对 Fraction class 的对象执行操作,所以我假设,在 Fraction 中声明的隐式应该被自动调用。我也尝试过显式导入隐式方法,但没有用。
请在下面找到代码片段以供参考。
package com.example.implicits.conversion
object ImplicitConversionTester extends App {
val f1 = Fraction(4,2)
val result = 2 * f1
println(s"${f1 * f1}")
println(s"${result}")
}
class Fraction(val numerator : Int,val denominator : Int) {
def *(fraction : Fraction): Fraction = {
println("##### Call to operator overloading *")
Fraction(this.numerator*fraction.numerator, this.denominator*fraction.denominator)
}
override def toString: String = s"Fraction($numerator,$denominator) ===== ${numerator/denominator}"
}
object Fraction {
def apply(numerator: Int, denominator: Int): Fraction = new Fraction(numerator, denominator)
implicit def intToFraction(num : Int) = {
println("##### intToFraction")
Fraction(num,1)
}
implicit def fractionToInt(fr : Fraction) = {
println("##### fractionToInt")
fr.numerator/fr.denominator
}
}
感谢任何解决此问题的建议!
你是对的,scala 编译器首先在
中查找隐式- 当时的当前范围
- 然后在伴随范围内
- 在导入范围内
在你的例子中,编译器在主单例对象的范围内寻找隐式 ImplicitConversionTester
并且它不会找到任何东西,因为没有任何隐式可用。如果你导入隐式那么它应该工作 -
object Implicit extends App {
import Fraction._
class Fraction(val numerator : Int,val denominator : Int) {
def * (fraction : Fraction): Fraction = {
println("##### Call to operator overloading *")
Fraction(this.numerator*fraction.numerator, this.denominator*fraction.denominator)
}
}
object Fraction {
def apply(numerator: Int, denominator: Int): Fraction = new Fraction(numerator, denominator)
implicit def intToFraction(num : Int) = {
println("##### intToFraction")
Fraction(num,1)
}
implicit def fractionToInt(fr : Fraction) = {
println("##### fractionToInt")
fr.numerator/fr.denominator
}
}
println(Fraction(1,2) * 2)
}
问题出在没有明确提及 return 类型的隐式方法声明中。我没有在上面的代码片段中提到 return 类型。添加函数 return 类型后,隐式函数工作正常。因此,无需在 ImplicitConversionTester class 中显式导入隐式函数来解决问题。
以下是修正错误的更新分数 class:
class Fraction(val numerator : Int,val denominator : Int) {
val test = 2
def *(fraction : Fraction): Fraction = {
println("##### Call to operator overloading *")
Fraction(this.numerator*fraction.numerator, this.denominator*fraction.denominator)
}
override def toString: String = s"Fraction($numerator,$denominator) ===== ${numerator/denominator}"
}
object Fraction {
def apply(numerator: Int, denominator: Int): Fraction = new Fraction(numerator, denominator)
implicit def intToFraction(num : Int) : Fraction = { // RETURN TYPE FRACTION
println("##### intToFraction")
Fraction(num,1)
}
implicit def fractionToInt(fr : Fraction) : Int = { // ADDED RETURN TYPE INT
println("##### fractionToInt")
fr.numerator/fr.denominator
}
}
在下面分享有关 Scala 编译器如何查找隐式转换的更多详细信息。下图摘自《Scala for the Impatient》一书。
如书中所述,Scala 编译器优先考虑 source 或 target 类型的伴随对象。
这里,什么是source和target类型,取决于表达式的顺序。例如,如果表达式是“2*Fraction(2,4)”,则表达式从左到右求值。整数“2”已经实现了乘法方法 (*)。因此,编译器首先尝试在“Int”类型中找到从“Fraction to Int”的隐式转换。由于“Int”类型没有“Fraction to Int”的任何实现,编译器将查找 Fraction class 的伴生对象,并在其中找到方法“fractionToInt”。在此示例中,目标类型为 Int,源类型为 Fraction。
考虑表达式 "Fraction(2,4)*2" 的示例,这里作为 Fraction class 具有可用于乘法 "*" 的实现,编译器试图找到将 Int 转换为 Fraction 的隐式。所以目标类型是 Fraction,Source 类型是 Int。由于 Int class 中不存在此类隐式 method/class,编译器查找 Fraction 伴随对象并找到“IntToFraction”隐式。