“什么是”呢;“隐藏的隐式值成员”;在Scala doc中?
文档中有一个隐藏的隐式值成员部分。例如: def拆分(arg0:String,arg1:Int):数组[String] 隐含信息“什么是”呢;“隐藏的隐式值成员”;在Scala doc中?,scala,Scala,文档中有一个隐藏的隐式值成员部分。例如: def拆分(arg0:String,arg1:Int):数组[String] 隐含信息 此成员是通过scala.Predef中的unauthengmentString方法执行的从StringOps到String的隐式转换添加的 阴影 该隐式继承的成员被该类中的一个或多个成员隐藏。 要访问此成员,可以使用类型归属: (stringOps: String).split(arg0, arg1) case class Foo(x :String) { de
此成员是通过scala.Predef中的unauthengmentString方法执行的从StringOps到String的隐式转换添加的 阴影
该隐式继承的成员被该类中的一个或多个成员隐藏。 要访问此成员,可以使用类型归属:
(stringOps: String).split(arg0, arg1)
case class Foo(x :String) {
def whoAmI = "Foo: " + x
}
implicit class Bar(foo: Foo) {
def whoAmI = "Bar: " + foo.x
}
println( Foo("test").whoAmI )
println( (Foo("test"): Bar).whoAmI )
定义类串 但当我尝试运行以下程序时:
“aaa bbb ccc”.split(“,2)/>res0:Array[String]=Array(aaa,bbb ccc)
调用String.split(arg0:String,arg1:Int)
不需要像文档中描述的那样使用类型归属
那么,隐藏的隐式值成员指的是什么?我试着问谷歌,但找不到任何参考资料
是不是有点像:
class A {
def foo() = println("foo")
}
class AOps(a: A) {
def bar() = println("bar")
def foo() = println("new foo")
def foo(i: Int) = println("foo %d".format(i))
}
object Program {
implicit def A2AOps(a: A) = new AOps(a) //> A2AOps: (a: A)AOps
val a = new A() //> a : A = A@15669ae
a.foo //> foo
a.bar //> bar
(a: AOps).foo //> new foo
a.foo(1) //> foo 1
}
然后String.split(…)
和StringOps.split
函数签名不同,因此不需要“类型归属”
这就是“隐藏的隐式值成员”的含义吗?我有点困惑。谢谢 “aaa bbb ccc”是字符串对象,而不是StringOps对象,因此注释不相关
在这种情况下,您可能永远不会显式创建StringOps对象,只会依赖隐式转换,因此Scaladoc注释似乎没有什么用处。Scaladoc告诉您可以在StringOps实例上调用的非StringOps方法。调用此方法将触发从StringOps到字符串的隐式转换 我们很少使用原始StringOps对象,因此实际上不太可能进行隐式转换 解释了类型归属
通常,当您调用给定类型不存在的方法时,Scala编译器将执行隐式转换:
case class Foo(x :String)
implicit class Bar(foo: Foo) {
def barOnly = "w00p"
}
println( Foo("test").barOnly )
这里,当我们在Foo
实例上调用方法barOnly
时,scala编译器可以看到它需要执行从Foo
到Bar
的隐式转换,以向我们提供该方法,并获得w00p
的预期输出
但是,如果Foo
和Bar
中存在具有相同签名的方法,则我们会有一些阴影,scala编译器不会进行隐式转换,除非我们明确要求使用类型归属:
(stringOps: String).split(arg0, arg1)
case class Foo(x :String) {
def whoAmI = "Foo: " + x
}
implicit class Bar(foo: Foo) {
def whoAmI = "Bar: " + foo.x
}
println( Foo("test").whoAmI )
println( (Foo("test"): Bar).whoAmI )
输出为:
Foo: test
Bar: test
在scaladocs中的split
示例中,在String
和StringOps
上都有名为split
的方法,但是它们采用不同的参数类型,所以我不完全清楚为什么文档会警告我们必须使用类型归属。在这种情况下,我们不需要为编译器消除任何歧义,类型归属没有任何效果:
import scala.collection.immutable.StringOps
val stringOps: StringOps = "aaa bbb ccc"
println( stringOps.split("a", 2).mkString )
println( (stringOps: String).split("a", 2).mkString )
这两条线的输出相同:
aa bbb ccc
aa bbb ccc
可能只是文档中的一个错误。当您有一个隐式类使用不同的签名重载该方法时,类型归属似乎是必要的。这与上面的其他答案相矛盾 以
TreeMap
的apply
方法为例。假设我想用一个取零索引整数位置的方法重载它,这样我就可以索引到TreeMap
中,就像它是一个数组一样:
implicit class MapIndexerExtension(m : TreeMap[Double,String]) {
def apply(idx : Int) = m.take(idx + 1).last
}
val m = TreeMap( 0.3333333 -> "A third",
2.71828 -> "Natural E",
3.142 -> "Pi") //> m : scala.collection.immutable.TreeMap[Double,String] = Map(0.3333333 -> A
//| third, 2.71828 -> Natural E, 3.142 -> Pi)
m(3.142) //> res0: String = Pi
(m: MapIndexerExtension)(2) //> res1: (Double, String) = (3.142,Pi)
m(2 : Int) //> java.util.NoSuchElementException: key not found: 2.0
m(2) //> java.util.NoSuchElementException: key
您会注意到最后几行失败了。这里发生的事情是2被转换成一个double,然后用TreeMap.apply查找,当然失败了。即使我们将其归因于:Int
不过res1还可以,因为我们在m
上使用类型归属
在Theon的回答中的示例中,您看不出StringOps和对拆分的字符串调用之间有任何区别,但我认为这是因为它们旨在产生相同的输出,即使它们的实现方式不同
为什么会这样,我不知道。如果你问我,我会很困惑;但我认为这是为了阻止人们做我在上面的例子中所展示的事情。“……但我认为这是因为它们应该产生相同的输出,即使它们的实现不同。”这是因为调用了类java.lang.String
中定义的相同方法<代码>字符串操作
没有拆分(arg0:String)