成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Groovy 語法 類型知識詳解,你明白了嗎?

開發 前端
本篇內容開始介紹Groovy中的各種類型知識。將會分多篇文章詳細介紹和學習Groovy中的有關于類型的相關知識點。內容來源于Groovy官方文檔中得到1.6.6. Typing中的相關知識點。

1. 介紹

本篇內容開始介紹Groovy中的各種類型知識。將會分多篇文章詳細介紹和學習Groovy中的有關于類型的相關知識點。

內容來源于Groovy官方文檔中得到1.6.6. Typing中的相關知識點。

內容比較多。可以通過目錄查詢想了解的模塊。

2. 可選類型-Optional typing

可選類型是指即使不在變量上設置顯式類型,程序也可以工作。作為一種動態語言,Groovy自然實現了這一特性,例如,當聲明一個變量時:

String aString = 'zinyan.com'   //聲明了一個變量字符串                    
//我們調用這個字符串的大小寫轉換方法并輸出
println aString.toUpperCase() //輸出:ZINYAN.COM

在Groovy中,我們可以通過可選類型關鍵字:def 來代替:

def aString = 'zinyan.com'   //聲明了一個變量字符串                    

println aString.toUpperCase()

兩種寫法是一樣的。def不只是可以代替String,它可以代替任何的一種數據類型。

所以在這里使用顯式類型并不重要。當我們將此功能與靜態類型檢查相結合時,這尤其有趣,因為類型檢查器執行類型推斷。

同樣,Groovy不強制在方法中聲明參數的類型:

String concat(String a, String b) {
a+b
}
println concat('zinyan','.com') //輸出:zinyan.com

可以使用def作為返回類型和參數類型來重寫,以便利用duck類型,如以下示例所示:

def concat(def a, def b) {                              
a+b
}
println concat('zinyan','.com') //輸出:zinyan.com
println concat(1,2) //輸出:3

我們通過def可選類型,就能實現動態的參數處理了。擴展了方法的使用范圍。

建議在這里使用def?關鍵字來描述一個方法的意圖,該方法應該適用于任何類型,但從技術上講,我們可以使用Object?,結果是一樣的:在Groovy中,def?嚴格等同于使用Object。

最終,可以從返回類型和描述符中完全刪除該類型。但如果要從返回類型中刪除它,則需要為該方法添加顯式修飾符,以便編譯器可以在方法聲明和方法調用之間產生差異,如以下示例所示:

private concat(a,b) {                                  
a+b
}
println concat('zinyan','.com') //輸出:zinyan.com
println concat(1,2) //輸出:3

我們直接將def給省略了。

在公共API的方法參數或方法返回類型中,省略類型通常被認為是一種不好的做法。雖然在局部變量中使用def?并不是一個真正的問題,因為變量的可見性僅限于方法本身,但在方法參數上設置def?時,def將在方法簽名中轉換為Object,這使得用戶很難知道哪種類型的參數是期望的類型。

PS:總結來說,我們可以將類型定義為def,然后還能將def給省略掉。但是不建議大家在對外提供的api中省略def。容易造成閱讀困難。

其次,def就是java中的Object對象。只是中間的各種轉換解析等功能Groovy在編譯器中幫我們進行了轉換。

3. 靜態類型檢測-Static type checking

默認情況下,Groovy在編譯時執行最小的類型檢查。由于它主要是一種動態語言,所以靜態編譯器通常無法在編譯時進行的大多數檢查。通過運行時元編程添加的方法可能會改變類或對象的運行時行為。

通過示例介紹一下:

//創建一個對象
class Person {
String firstName
String lastName
}
//初始化該實例對象
def p = new Person(firstName: 'Zin', lastName: 'yan')
println p.formattedName

在動態語言中,像上述示例這樣的代碼不拋出任何錯誤是很常見的。在Java中,這通常會在編譯時失敗。

我們直接執行上面的代碼就會輸出:

Caught: groovy.lang.MissingPropertyException: No such property: formattedName for class: Person
groovy.lang.MissingPropertyException: No such property: formattedName for class: Person
at zinyan.run(zinyan.groovy:8)

錯誤提示,我們如果想正常運行,就需要執行依賴運行時元編程。也就是說修改運行時狀態,執行動態特性:

Person.metaClass.getFormattedName = { "$delegate.firstName $delegate.lastName" }

完整示例為:

//創建一個對象
class Person {
String firstName
String lastName
}
//初始化該實例對象
Person.metaClass.getFormattedName = { "$delegate.firstName $delegate.lastName" }
def p = new Person(firstName: 'Zin', lastName: 'yan')
println p.formattedName

這意味著,一般來說,在Groovy中,除了聲明類型之外,我們不能對對象的類型做出任何假設,即使我們知道它,也無法在編譯時確定將調用什么方法,或者將檢索哪個屬性。這個特性用在DSL和測試腳本編寫中有不少的特性。這里就不展開了。

然而,如果我們的程序不依賴動態特性,并且來自靜態世界(特別是來自Java思維),那么在編譯時沒有捕捉到這樣的“錯誤”可能會出現崩潰。正如我們在前面的示例中看到的,編譯器不能確定這是一個錯誤。為了讓編譯器意識到這一點,必須明確指示編譯器我們正在切換到類型檢查模式。這可以通過使用

@groovy.transform.TypeChecked注釋類或方法來完成。

當激活類型檢查時,編譯器將新增以下的工作:

類型推斷被激活,這意味著即使對局部變量使用def,類型檢查器也能夠從賦值中推斷出變量的類型.

方法調用在編譯時解析,這意味著如果沒有在類上聲明方法,編譯器將拋出錯誤

通常,在靜態語言中查找的所有編譯時錯誤都會出現:方法未找到、屬性未找到、方法調用的不兼容類型、數字精度錯誤等…

下面讓我們描述類型檢查器在各種情況下的行為,并解釋在代碼中使用@TypeChecked的限制。

3.1 @TypeChecked注解

在編譯時激活類型檢查。

我們可以將@groovy.transform.TypeChecked注解添加到類的開頭,

讓編譯器編譯該類時啟用類型檢測:

@groovy.transform.TypeChecked
class Calculator {
int sum(int x, int y) { x+y }
}

或添加到方法中:

class Calculator {
@groovy.transform.TypeChecked
int sum(int x, int y) { x+y }
}

在第一種情況下,所有方法、屬性、字段、內部類… 注釋類的類型將被檢查,而在第二種情況下,只有方法和它包含的潛在閉包或匿名內部類將被類型檢查。

我們同時也可以通過@TypeChecked(TypeCheckingMode.skip)對其進行注釋來指示類型檢查器跳過類型檢測:

import groovy.transform.TypeChecked
import groovy.transform.TypeCheckingMode
//對GreetingService類的所有方法和類進行類型檢測。
@TypeChecked
class GreetingService {
String greeting() {
doGreet()
}
//對doGreet方法跳過類型檢測。
@TypeChecked(TypeCheckingMode.SKIP)
private String doGreet() {
def b = new SentenceBuilder()
b.Hello.my.name.is.Zinyan
b
}
}
def s = new GreetingService()
assert s.greeting() == 'Hello my name is Zinyan'

在前面的示例中,SentenceBuilder?依賴于動態代碼。沒有真正的Hello?方法或屬性,因此類型檢查器通常會發出異常,編譯將失敗。因為使用生成器的方法被標記為TypeCheckingMode.SKIP,此方法跳過了類型檢查,因此即使類的其余部分進行了類型檢查也會編譯代碼。

以下部分描述Groovy中類型檢查的語義。

3.2 類型檢查分配

類型A?的對象o?可以賦值給類型T的變量當且僅當:

  • T? 等于A。
  • 或者T? 是以下幾種類型之一:String?, boolean?, Boolean? 或Class。
  • 或者o? 是空的,T不是一個基本類型。
  • 或者T和A? 是一個數組, A? 的組件類型可分配給 T 的組件類型。
  • 或者T? 是一個數組,A? 是一個集合或流(stream ), A?的組件類型可分配給 T的組件類型。
  • 或者T? 是 A 的超類。
  • 或者T?是由 A 實現的接口。
  • 或者T?或 A 是基本類型,它們的封裝類型是可賦值的。
  • 或者T?extedns groovy.lang.Closure?是一個閉包,同時A 是SAM類型(單一抽象方法類型)。
  • 或者T和A?源自java.lang. Number,并遵循下表:

T

A

Examples

Double

Any but BigDecimal or BigInteger

??Double d1 = 4d Double d2 = 4f Double d3 = 4l Double d4 = 4i Double d5 = (short) 4 Double d6 = (byte) 4??

Float

Any type but BigDecimal, BigInteger or Double

??Float f1 = 4f Float f2 = 4l Float f3 = 4i Float f4 = (short) 4 Float f5 = (byte) 4??

Long

Any type but BigDecimal, BigInteger, Double or Float

??Long l1 = 4l Long l2 = 4i Long l3 = (short) 4 Long l4 = (byte) 4??

Integer

Any type but BigDecimal, BigInteger, Double, Float or Long

??Integer i1 = 4i Integer i2 = (short) 4 Integer i3 = (byte) 4??

Short

Any type but BigDecimal, BigInteger, Double, Float, Long or Integer

??Short s1 = (short) 4 Short s2 = (byte) 4??

Byte

Byte

??Byte b1 = (byte) 4??

3.3 List 和Map 的構造函數

除了上面的賦值規則,如果賦值被認為是無效的,在類型檢查模式下,如果滿足以下條件,List或Map A?可以賦值給類型T的變量:

賦值是一個變量聲明,A?是一個List,T有一個構造函數,其參數與List的元素類型匹配。

賦值是一個變量聲明,A是一個map,T有一個無參數構造函數,每個map鍵都有一個屬性。

具體示例如下:

@groovy.transform.TupleConstructor
class Person {
String firstName
String lastName
}
Person classic = new Person('Zin','yan')

可以使用“列表構造函數”:

Person list = ['Zin','yan']

創建一個Person對象出來,也可以使用Map構造函數創建一個Person對象:

Person map = [firstName:'Zin', lastName:'yan']

如果使用Map構造函數,則會對映射的鍵進行額外檢查,以檢查是否定義了同名的屬性。例如,以下代碼將在編譯時失敗:

@groovy.transform.TupleConstructor
class Person {
String firstName
String lastName
}
Person map = [firstName:'Zin', lastName:'yan', age: 1024]

就會觸發以下錯誤:

org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object '{firstName=Zin, lastName=yan, age=1024}' with class 'java.util.LinkedHashMap' to class 'Person' due to: org.codehaus.groovy.runtime.metaclass.MissingPropertyExceptionNoStack: No such property: age for class: Person

3.4 方法解析

在類型檢查模式下,方法在編譯時解析。解析通過名稱和參數工作。返回類型與方法選擇無關。參數類型與以下規則中的參數類型匹配:

類型A?的參數o?可以用于類型T的參數,當且僅當:

  • T? 等于A。
  • 或者T?是一個String,A?是一個GString。
  • 或者o?為空,T不是基礎類型。
  • 或者T?是一個數組,A?是一個數組,A?的組件類型可以分配給T的組件類型。
  • 或者T是A的超類。
  • 或者T是A實現的接口。
  • 或者T或A是基本類型,它們的封裝類型是可賦值的。
  • 或T?擴展了groovy.lang.Closure?,而A是SAM類型(單一抽象方法類型)。
  • 或者T和A?派生自java.lang.Number,并遵循與數字賦值相同的規則。

如果在編譯時沒有找到具有適當名稱和參數的方法,則拋出錯誤。下面的例子說明了與“正常”Groovy的區別:

class MyService {
void doSomething() {
printLine 'Do something'
}
}

printLine是一個錯誤,但由于我們處于動態模式,錯誤在編譯時不會被捕獲

上面的例子展示了一個Groovy能夠編譯的類。但是,如果嘗試創建MyService?的實例并調用doSomething?方法,那么它將在運行時失敗,因為printLine?不存在。當然,我們已經展示了Groovy如何使它成為一個完全有效的調用,例如通過捕獲MethodMissingException?或實現一個自定義元類,但如果你知道你不是在這種情況下,@typecheck會派上用場:

@groovy.transform.TypeChecked
class MyService {
void doSomething() {
printLine 'Do something'
}
}

僅僅添加@typecheck?就會觸發編譯時方法解析。類型檢查器將嘗試在MyService?類上找到一個接受String的方法printLine,如果找不到。它將編譯失敗,并顯示以下消息:

Cannot find matching method MyService#printLine(java.lang.String)

理解類型檢查器背后的邏輯很重要:它是一種編譯時檢查,因此根據定義,類型檢查器不知道我們所做的任何類型的運行時元編程。這意味著如果激活類型檢查,沒有@TypeChecked也完全有效的代碼將不再編譯。如果你想到duck typing,這一點尤其重要:

class Duck {
void quack() {
println 'Quack!'
}
}
class QuackingBird {
void quack() {
println 'Quack!'
}
}
@groovy.transform.TypeChecked
void accept(quacker) {
quacker.quack()
}
accept(new Duck())

比如引入一個接口,但基本上,通過激活類型檢查,獲得了類型安全,但失去了語言的一些特性。希望Groovy能引入一些特性,比如流類型,以縮小類型檢查和非類型檢查Groovy之間的差距。

4. 小結

本篇內容未完待續。可以通過下一篇了解完整內容。

以上內容參考Groovy 官方文檔:http://docs.groovy-lang.org/docs/groovy-4.0.6/html/documentation/#_typing

責任編輯:武曉燕 來源: zinyan
相關推薦

2023-01-04 08:39:34

2022-12-28 08:03:02

Groovy語法GPath

2022-12-30 08:35:00

2023-12-28 08:43:28

前端算法搜索

2024-01-08 20:05:32

2022-10-19 08:19:32

動態基線預警

2022-04-07 11:15:22

PulseEventAPI函數

2023-12-08 08:38:15

EventLoopAPI瀏覽器

2022-10-10 18:38:56

inert屬性鍵盤

2024-12-31 00:08:37

C#語言dynamic?

2022-12-26 08:36:53

Groovy語法控制結構

2015-09-18 09:17:06

數據分析

2022-10-08 08:09:13

MGRGreatSQL事務

2022-03-05 17:56:29

桌面應用開發

2023-12-06 08:01:03

CSSPostCSS

2023-06-14 08:15:34

算法合并操作Winner

2024-03-27 13:33:00

MySQLInnoDB事務

2022-10-24 20:25:40

云原生SpringJava

2024-08-09 13:39:27

2022-05-04 08:38:32

Netty網絡框架
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 日韩精品视频在线 | 91亚洲国产精品 | 国产一区二区精品在线 | 久久久精彩视频 | 超碰人人插 | 91麻豆精品国产91久久久久久久久 | 91福利在线观看视频 | 国产1区在线 | 国产四区 | 久久久九九 | 一本色道久久综合亚洲精品高清 | 欧美区在线观看 | 精品福利av导航 | 一区二区三区精品视频 | 国产免国产免费 | 日韩视频免费看 | 欧美日韩视频 | 精品亚洲一区二区三区 | 天天干夜夜操 | 欧美一区二区成人 | 成人av看片 | 超碰在线97国产 | 亚洲一区二区三区观看 | 自拍偷拍在线视频 | 亚洲天堂久久 | 成人区一区二区三区 | 国产一级在线 | 欧美日韩中文字幕在线 | 欧美日韩在线不卡 | 欧美日韩国产免费 | 岛国在线免费观看 | 亚洲三级视频 | 高清国产午夜精品久久久久久 | 午夜免费精品视频 | 亚洲精品粉嫩美女一区 | 日日夜夜精品视频 | 在线中文字幕av | 精产国产伦理一二三区 | 国产h视频 | 国产精品毛片无码 | 99久久精品免费看国产四区 |