深入理解Scala的隱式轉換系統

原文鏈接:http://www.cnblogs.com/MOBIN/p/5351900.html
----------------------------------------------
摘要:
通過隱式轉換,程序員可以在編寫Scala程序時故意漏掉一些信息,讓編譯器去嘗試在編譯期間自動推導出這些信息來,這種特性可以極大的減少代碼量,忽略那些冗長,過于細節的代碼。
使用方式:
1.將方法或變量標記為implicit
2.將方法的參數列表標記為implicit
3.將類標記為implicit
Scala支持兩種形式的隱式轉換:
隱式值:用于給方法提供參數
隱式視圖:用于類型間轉換或使針對某類型的方法能調用成功
隱式值:
例1:聲明person方法。其參數為name,類型String
scala> def person(implicit name : String) = name   //name為隱式參數
person: (implicit name: String)String
直接調用person方法
scala> person
<console>:9: error: could not find implicit value for parameter name: Stringperson^
報錯!編譯器說無法為參數name找到一個隱式值
定義一個隱式值后再調用person方法
scala> implicit val p = "mobin"   //p被稱為隱式值
p: String = mobin
scala> person
res1: String = mobin
因為將p變量標記為implicit,所以編譯器會在方法省略隱式參數的情況下去搜索作用域內的隱式值作為缺少參數。
但是如果此時你又在REPL中定義一個隱式變量,再次調用方法時就會報錯
復制代碼
scala> implicit val p1 = "mobin1"
p1: String = mobin1
scala> person
<console>:11: error: ambiguous implicit values:both value p of type => Stringand value p1 of type => Stringmatch expected type Stringperson^
復制代碼
匹配失敗,所以隱式轉換必須滿足無歧義規則,在聲明隱式參數的類型是最好使用特別的或自定義的數據類型,不要使用Int,String這些常用類型,避免碰巧匹配
隱式視圖
隱式轉換為目標類型:把一種類型自動轉換到另一種類型
例2:將整數轉換成字符串類型:
復制代碼
scala> def foo(msg : String) = println(msg)
foo: (msg: String)Unitscala> foo(10)
<console>:11: error: type mismatch;
found : Int(10)
required: String
foo(10)
^
復制代碼
顯然不能轉換成功,解決辦法就是定義一個轉換函數給編譯器將int自動轉換成String
scala> implicit def intToString(x : Int) = x.toString
intToString: (x: Int)Stringscala> foo(10)
10
隱式轉換調用類中本不存在的方法
例3:通過隱式轉換,使對象能調用類中本不存在的方法
復制代碼
class SwingType{def  wantLearned(sw : String) = println("兔子已經學會了"+sw)
}
object swimming{implicit def learningType(s : AminalType) = new SwingType
}
class AminalType
object AminalType extends  App{import com.mobin.scala.Scalaimplicit.swimming._val rabbit = new AminalTyperabbit.wantLearned("breaststroke")         //蛙泳
}
復制代碼
編譯器在rabbit對象調用時發現對象上并沒有wantLearning方法,此時編譯器就會在作用域范圍內查找能使其編譯通過的隱式視圖,找到learningType方法后,編譯器通過隱式轉換將對象轉換成具有這個方法的對象,之后調用wantLearning方法
可以將隱式轉換函數定義在伴生對象中,在使用時導入隱式視圖到作用域中即可(如例4的learningType函數)
還可以將隱式轉換函數定義在兇對象中,同樣在使用時導入作用域即可,如例4
例4:
復制代碼
class SwingType{def  wantLearned(sw : String) = println("兔子已經學會了"+sw)
}package swimmingPage{
object swimming{implicit def learningType(s : AminalType) = new SwingType  //將轉換函數定義在包中
  }
}
class AminalType
object AminalType extends  App{import com.mobin.scala.Scalaimplicit.swimmingPage.swimming._  //使用時顯示的導入val rabbit = new AminalTyperabbit.wantLearned("breaststroke")         //蛙泳
}
復制代碼
像intToString,learningType這類的方法就是隱式視圖,通常為Int => String的視圖,定義的格式如下:
? ? ?implicit def ?originalToTarget (<argument> : OriginalType) : TargetType
其通常用在于以兩種場合中:
1.如果表達式不符合編譯器要求的類型,編譯器就會在作用域范圍內查找能夠使之符合要求的隱式視圖。如例2,當要傳一個整數類型給要求是字符串類型參數的方法時,在作用域里就必須存在Int => String的隱式視圖
2.給定一個選擇e.t,如果e的類型里并沒有成員t,則編譯器會查找能應用到e類型并且返回類型包含成員t的隱式視圖。如例3
隱式類:
在scala2.10后提供了隱式類,可以使用implicit聲明類,但是需要注意以下幾點:
1.其所帶的構造參數有且只能有一個
2.隱式類必須被定義在類,伴生對象和包對象里
3.隱式類不能是case class(case class在定義會自動生成伴生對象與2矛盾
4.作用域內不能有與之相同名稱的標示符
例5:
復制代碼
object Stringutils {implicit class StringImprovement(val s : String){   //隱式類def increment = s.map(x => (x +1).toChar)}
}
object  Main extends  App{import com.mobin.scala.implicitPackage.Stringutils._println("mobin".increment)
}
復制代碼
編譯器在mobin對象調用increment時發現對象上并沒有increment方法,此時編譯器就會在作用域范圍內搜索隱式實體,發現有符合的隱式類可以用來轉換成帶有increment方法的StringImprovement類,最終調用increment方法。

隱式轉換的時機:

1.當方法中的參數的類型與目標類型不一致時

2.當對象調用類中不存在的方法或成員時,編譯器會自動將對象進行隱式轉換
隱式解析機制
即編譯器是如何查找到缺失信息的,解析具有以下兩種規則:
1.首先會在當前代碼作用域下查找隱式實體(隱式方法 ?隱式類 隱式對象)
2.如果第一條規則查找隱式實體失敗,會繼續在隱式參數的類型的作用域里查找
類型的作用域是指與該類型相關聯的全部伴生模塊,一個隱式實體的類型T它的查找范圍如下:
(1)如果T被定義為T with A with B with C,那么A,B,C都是T的部分,在T的隱式解析過程中,它們的伴生對象都會被搜索
(2)如果T是參數化類型,那么類型參數和與類型參數相關聯的部分都算作T的部分,比如List[String]的隱式搜索會搜索List的
伴生對象和String的伴生對象
(3) 如果T是一個單例類型p.T,即T是屬于某個p對象內,那么這個p對象也會被搜索
(4) 如果T是個類型注入S#T,那么S和T都會被搜索
隱式轉換的前提:
1.不存在二義性(如例1)
?
2.隱式操作不能嵌套使用(如 convert1(covert2(x)))+y
?
3.代碼能夠在不使用隱式轉換的前提下能編譯通過,就不會進行隱式黑鐵

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/538419.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/538419.shtml
英文地址,請注明出處:http://en.pswp.cn/news/538419.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

python123輸出最大值_Python:運行另一列的最大值?

我有一個像這樣的數據幀&#xff0c;它跟蹤特定項(ID)的值隨時間的變化&#xff1a;mytimenp.tile( np.arange(0,10) , 2 )myidsnp.repeat( [123,456], [10,10] )myvaluesnp.random.random_integers(20,30,10*2)dfpd.DataFrame()df[myids]myidsdf[mytime]mytimedf[myvalues]myv…

Java連接MySQL

2019獨角獸企業重金招聘Python工程師標準>>> <1> 在navicat中創建一個MySQL連接&#xff0c;填寫連接名和密碼&#xff08;密碼為你配置MySQL設置的密碼&#xff09; <2> 在該連接中新建一個數據庫&#xff0c;填寫數據庫名。字符集選擇&#xff08;gb-…

ssm實訓報告心得_Java開發學習心得(一):SSM環境搭建

Java開發學習心得&#xff08;一&#xff09;&#xff1a;SSM環境搭建有一點.NET的開發基礎&#xff0c;在學校學過基礎語法&#xff0c;對JAVA有點興趣&#xff0c;就簡單學習了一下&#xff0c;記錄一下從哪些方面入手的&#xff0c;暫時不打算深入到原理方面&#xff0c;先簡…

Java中boolean類型占用多少個字節

原文地址&#xff1a;http://www.cnblogs.com/wangtianze/p/6690665.html?utm_sourceitdadao&utm_mediumreferral ----------------------- 為什么要問這個問題&#xff0c;首先在Java中定義的八種基本數據類型中&#xff0c;除了其它七種類型都有明確的內存占用字節數外…

java虛引用作用_深入理解Java中的引用(二)——強軟弱虛引用

深入理解Java中的引用(二)——強軟弱虛引用在上一篇文章中介紹了Java的Reference類&#xff0c;本篇文章介紹他的四個子類&#xff1a;強引用、軟引用、弱引用、虛引用。強引用(StrongReference)強引用是我們在代碼中最普通的引用。示例代碼如下&#xff1a;Object o new Obje…

SQL查詢表的列名

SELECT COLUMN_NAME FROM DBA_TAB_COLUMNS WHERE TABLE_NAME DT4_JOB_CHECK_MATRIX;SELECT COLUMN_NAME FROM ALL_TAB_COLUMNS WHERE TABLE_NAME DT4_JOB_CHECK_MATRIX;SELECT COLUMN_NAME FROM USER_TAB_COLUMNS WHERE TABLE_NAME DT4_JOB_CHECK_MATRIX;

java老鳥123怎么樣_java入門123——一個老鳥的java學習心得.doc

java入門123——一個老鳥的java學習心得java入門123——一個老鳥的java學習心得篇一&#xff1a;java初學者學習心得學習Java心得體會學習了一學期的Java課程,覺得是該總結自己的心得體會了。開始學習任何一門課(包括java)&#xff0c;興趣最重要。一直覺得自己在學計算機編程語…

ruby 爬蟲爬取拉鉤網職位信息,產生詞云報告

思路&#xff1a;1.獲取拉勾網搜索到職位的頁數 2.調用接口獲取職位id 3.根據職位id訪問頁面&#xff0c;匹配出關鍵字 url訪問采用unirest&#xff0c;由于拉鉤反爬蟲&#xff0c;短時間內頻繁訪問會被限制訪問&#xff0c;所以沒有采用多線程&#xff0c;而且每個頁面訪問時間…

評論語義分析 分詞 分類python_用python調用ICTCLAS50進行中文分詞

直接上源碼吧tokenizer類&#xff1a;#_*_encoding:utf-8_*_from ctypes import *class tokenizer:def __init__(self):self._stext[、,“,”,&#xff0c;,。,《,》,&#xff1a;,&#xff1b;,!,‘,’,?,&#xff1f;,&#xff01;,, ,] #枚舉標點符號包括空格self._stopwor…

java對日期Date類進行加減運算、年份加減,月份加減

JAVA處理日期時間常用方法&#xff1a; 1.Java.util.Calendar Calendar 類是一個抽象類&#xff0c;它為特定瞬間與一組諸如 YEAR、MONTH、DAY_OF_MONTH、HOUR 等 日歷字段之間的轉換提供了一些方法&#xff0c;并為操作日歷字段&#xff08;例如獲得下星期的日期&#xff09…

idle擴展插件_Python3.4學習筆記之 idle 清屏擴展插件用法分析

本文實例講述了Python3.4 idle 清屏擴展插件用法。分享給大家供大家參考&#xff0c;具體如下&#xff1a;python idle 清屏問題的解決&#xff0c;使用python idle都會遇到一個常見而又懊惱的問題——要怎么清屏?在stackoverflow看到這樣兩種答案&#xff1a;1.在shell中輸入…

內存堆和棧的區別

原文鏈接&#xff1a;http://www.cnblogs.com/lln7777/archive/2012/03/14/2396164.html -------------------------------------------------------------------------------- 在計算機領域&#xff0c;堆棧是一個不容忽視的概念&#xff0c;我們編寫的C語言程序基本上都要用…

MYSQL安裝和配置

Win10安裝MySQL5.7.22 解壓縮版&#xff08;手動配置 1.下載地址&#xff1a;https://dev.mysql.com/downloads/mysql/5.7.html#downloads 直接點擊下載項 下載后&#xff1a; 2.可以把解壓的內容隨便放到一個目錄&#xff0c;我的是如下目錄&#xff08;放到C盤的話&#xff0…

python刪除過期文件_python刪除過期文件的方法

本文實例講述了python刪除過期文件的方法。分享給大家供大家參考。具體實現方法如下&#xff1a;# remove all jpeg image files of an expired modification date mtime# you could also use creation date (ctime) or last access date (atime)# os.stat(filename) returns …

【很久之前的一篇老文章】一位程序員工作10年總結的13個忠告

展望未來&#xff0c;總結過去10年的程序員生涯&#xff0c;給程序員小弟弟小妹妹們的一些總結性忠告。 走過的路&#xff0c;回憶起來是那么曲折&#xff0c;把自己的一些心得體會分享給程序員兄弟姐妹們&#xff0c;雖然時代在變化&#xff0c;但是很可能你也會走我已經做過的…

apply()與call()的區別

一直都沒太明白apply()與call()的具體使用原理&#xff0c;今日閑來無事&#xff0c;決定好好研究一番。 JavaScript中的每一個Function對象都有一個apply()方法和一個call()方法&#xff0c;它們的語法分別為&#xff1a; /*apply()方法*/ function.apply(thisObj[, argArray]…

java代碼執行了兩次_Java中JComboBox的itemStateChanged事件執行兩次的解釋

今天做項目&#xff0c;用到了JComboBox&#xff0c;即下拉列表框。為了在被選中的項發生改變時獲得被選中的項&#xff0c;所以使用的ItemStateChanged事件&#xff0c;可是問題就來了&#xff0c;每次觸發該事件&#xff0c;它都執行兩次&#xff0c;屢試不爽。一開始以為是代…

python連接mongo_使用簡單的Python連接訪問MongoDB

繼續來聊MongoDB。MongoDB作為了一個數據庫產品軟件&#xff0c;除了服務器Server端進程(mongod)外&#xff0c;還提供了比較豐富的訪問連接接口。我們最常用的就是兩個類型&#xff0c;一個是原生mongo shell&#xff0c;另一個就是應用程序語言訪問接口。1、從Mongo Shell到應…

spring與mybatis三種整合方法

原文鏈接&#xff1a;http://www.cnblogs.com/wangmingshun/p/5674633.html ------------------------------------------------------------------------------------------------- 1、采用MapperScannerConfigurer&#xff0c;它將會查找類路徑下的映射器并自動將它們創建成…

js常用的2中排序方法:冒泡排序和快速排序

冒泡排序&#xff1a;例如9 4 5 6 8 3 2 7 10 1 首先&#xff1a;9和4比較 4放前 4 9 5 6 8 3 2 7 10 1 4和5比較 4不動 4 9 5 6 8 3 2 7 10 1 4和6比較 4不動 4 9 5 6 8 3 2 7 10 1 4和3比較 3放前 3 9 5 6 8 4 2 7 10 1 3和2比較 2放前 2 9 5 6 8…