從"hello".count想到的之二--scal
string隱式轉換的二義性問題
scala標準庫在中定義了兩個String的隱式轉換:
implicit def augmentString(x: String): StringOps implicit def wrapString(s: String): WrappedString
而StringOps
和WrappedString
有一些重複的方法,如count
:
中定義了count
方法
def count(p: (Char) Boolean): Int Counts the number of elements in the traversable or iterator which satisfy a predicate.
也有count
方法
def count(p: (Char) Boolean): Int Counts the number of elements in the traversable or iterator which satisfy a predicate.
�兩個count
方法��完全一樣,應該存在二義性問題啊。試著在REPL
中寫了�一�段隱式轉換的程式碼,果然會提示有二義性:
case class A1(a: Int) { def guess = a * 10}case class A2(a: Int) { def guess = a * 100} implicit def Int2A1(a: Int) = new A1(a) implicit def Int2A2(a: Int) = new A2(a) scala> 1.guess <console>:14: error: type mismatch; found : Int(1) required: ?{def guess: ?}Note that implicit conversions are not applicable because they are ambiguous: both method Int2A1 of type (a: Int)A1 and method Int2A2 of type (a: Int)A2 are possible conversion functions from Int(1) to ?{def guess: ?} 1.guess ^ <console>:14: error: value guess is not a member of Int 1.guess
但是從可以知道"hello".count
不但沒有報錯,還會選擇StringOps.count
。�為什麼會這樣呢?
�隱式轉換的最佳化級
在Martin Odersky
親自寫的《Programming in Scala(Third Edition)》21.7節最後有下面這一段說明:
The old implicit conversion to a Scala collection (now named WrappedString) is retained. However, there is a more specific conversion supplied fromString to a new type called StringOps. StringOps has many methods such as reverse, but instead of returning a collection, they return a String. The conversion to StringOps is defined directly in Predef, whereas the conversion to a Scala collection is defined in a new class, LowPriorityImplicits, which is extended by Predef. Whenever a choice exists between these two conversions, the compiler chooses the conversion to StringOps, because it's defined in a subclass of the class where the other conversion is defined.
簡而言之,編譯器之所以會選擇StringOps
而不是WrappedString
,是因為StringOps
更特化
(more specific)。為什麼說StringOps
更特化呢?讓�我們先看看的�繼承關係:
object Predef extends LowPriorityImplicits with DeprecatedPredef { /* ��忽略了很多�東東... */ /** @group conversions-string */ @inline implicit def augmentString(x: String): StringOps = new StringOps(x) }private[scala] abstract class LowPriorityImplicits { /* ��忽略了很多�東東... */ /** @group conversions-string */ implicit def wrapString(s: String): WrappedString = if (s ne null) new WrappedString(s) else null}
String
到StringOps
的隱式轉換是定義在Predef
物件中的,而String
到WrappedString
的�隱式轉換是在定義在Predef
的���父類LowPriorityImplicits
中,所以前者比後者更特化。
�還是在《Programming in Scala(Third Edition)》21.7節,有一��段更詳細的說明:
one implicit conversion is more specific than another if one of the following applies:
The argument type of the former is a subtype of the latter's.
Both conversions are methods, and the enclosing class of the former extends the enclosing class of the latter.
Odersky�又解釋道:
The motivation to revisit this issue and revise the rule was to improve interoperation between Java collections, Scala collections, and strings.
又試著在REPL寫了一段測試程式碼,的確如此:
case class A1(a: Int) { def guess = a * 10 def what = a}case class A2(a: Int) { def guess = a * 100} class BaseImplicits { implicit def Int2A1(a: Int) = new A1(a) } object SpecificImplicits extends BaseImplicits { implicit def Int2A2(a: Int) = new A2(a) } scala> import SpecificImplicits._import SpecificImplicits._scala> 1.guessres1: Int = 100scala> 1.whatres2: Int = 1
作者:typesafe
連結:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/1795/viewspace-2818785/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- MySQL的COUNT語句--count(*)、 count(常量)、 count(列名)MySql
- 從零搭建Spring Boot的Hello WorldSpring Boot
- count(*)、count(1)和count(列名)的區別
- 從 電影《飛馳人生》中想到
- 144.從拼多多優惠券事件想到的事件
- count (*) 和 count (1) 和 count (列名) 區別
- count(*) 和 count(1)和count(列名)區別
- Hello Spark! | Spark,從入門到精通Spark
- 從String型別發散想到的一些東西型別
- SQL Server中count(*)和Count(1)的區別SQLServer
- 圖解MySQL:count(*) 、count(1) 、count(主鍵欄位)、count(欄位)哪個效能最好?圖解MySql
- mysql count()的使用解析MySql
- [20180727]再論count(*)和count(1).txt
- 7.65 COUNT
- 洞見RSA 2021| ICS安全威脅——從假想到現實
- 由引數URL想到的
- react的”Hello World !“React
- WebGL 的 Hello WorldWeb
- C# 中List中的Count和Count(),有什麼區別C#
- hello
- MySQL:count(*) count(欄位) 實現上區別MySql
- String s = “hello“和String s = new String(“hello“)的區別
- 從同步函式 hello-world-dotnet 開始探索OpenFunction函式Function
- Count BFS Graph
- count(*) 優化優化
- Terraform中的for_each和countORM
- 關於count函式的理解函式
- word_count的scala學習
- Hello World
- Hello World!
- Hello, World
- Hello Word!
- Hello,cnblogs
- "HELLO BOKEYUAN"
- Hello,find!
- hello word
- Hello World !
- Hello,Threadthread