如何在Kotlin中使用局部方法?相信很多沒有經(jīng)驗的人對此束手無策,為此本文總結(jié)了問題出現(xiàn)的原因和解決方法,通過這篇文章希望你能解決這個問題。
成都創(chuàng)新互聯(lián)公司長期為上千多家客戶提供的網(wǎng)站建設(shè)服務(wù),團隊從業(yè)經(jīng)驗10年,關(guān)注不同地域、不同群體,并針對不同對象提供差異化的產(chǎn)品和服務(wù);打造開放共贏平臺,與合作伙伴共同營造健康的互聯(lián)網(wǎng)生態(tài)環(huán)境。為府谷企業(yè)提供專業(yè)的成都網(wǎng)站設(shè)計、成都做網(wǎng)站,府谷網(wǎng)站改版等技術(shù)服務(wù)。擁有10余年豐富建站經(jīng)驗和眾多成功案例,為您定制開發(fā)。在Kotlin中,定義方法很有趣,不僅僅因為方法的關(guān)鍵字是fun(function前幾個字符),還是因為你會驚奇的發(fā)現(xiàn),它允許我們在方法中定義方法。如下
fun methodA() { fun methodB() { } methodB() //valid } //methodB() invalid
其中
methodB定義在methodA的方法體中,即methodB被稱為局部方法或局部函數(shù)
methodB只能在methodA中方法調(diào)用
methodB在methodA方法外調(diào)用,會引起編譯錯誤
既然Kotlin支持了局部方法,相比它應(yīng)該有什么特殊的用武之地呢
首先它的特點還是像它的名字一樣,局部,這就意味著它有著無可比擬的更小范圍的限定能力。保證了小范圍的可用性,隔絕了潛在的不相關(guān)調(diào)用的可能。
作為編程中的金科玉律,方法越小越好,相比縱向冗長的代碼片段,將其按照職責切分成功能單一的小的局部方法,最后組織起來調(diào)用,會讓我們的代碼顯得更加的有條理和清晰。
作為一個程序員,好奇應(yīng)該是他的特質(zhì)之一,我們應(yīng)該會想要研究一下,局部方法的實現(xiàn)原理是什么,至少我們在Java時代從來沒有見過這種概念。
其實這件事仔細研究起來,還是有不少細節(jié)的。因為這其中局部方法可以捕獲外部的變量也可以不捕獲外部的變量。
下面就是捕獲外部變量的一種情況
fun outMethodCapture(args: Array<String>) { fun checkArgs() { if (args.isEmpty()) { println("innerMethod check args") Throwable().printStackTrace() } } checkArgs() }
這其中,局部方法checkArgs捕獲了outMethodCapture的參數(shù)args。
所以,不捕獲外部變量的情況也不難理解,如下,即checkArgs處理args都是通過參數(shù)傳遞的。
fun outMethodNonCapture(args: Array<String>) { fun checkArgs(args: Array<String>) { if (args.isEmpty()) { println("outMethodNonCapture check args") Throwable().printStackTrace() } } checkArgs(args) }
首先我們分析一下捕獲變量的局部方法的實現(xiàn)原理
public static final void outMethodCapture(@NotNull final String[] args) { Intrinsics.checkParameterIsNotNull(args, "args"); <undefinedtype> checkArgs$ = new Function0() { // $FF: synthetic method // $FF: bridge method public Object invoke() { this.invoke(); return Unit.INSTANCE; } public final void invoke() { Object[] var1 = (Object[])args; if(var1.length == 0) { String var2 = "innerMethod check args"; System.out.println(var2); (new Throwable()).printStackTrace(); } } }; checkArgs$.invoke(); }
如上實現(xiàn)原理,就是局部方法實現(xiàn)其實就是實現(xiàn)了一個匿名內(nèi)部類的實例,然后再次調(diào)用即可。 對于不捕獲的局部方法要稍有不同,首先我們反編譯得到對應(yīng)的Java代碼
public static final void outMethodNonCapture(@NotNull String[] args) { Intrinsics.checkParameterIsNotNull(args, "args"); <undefinedtype> checkArgs$ = null.INSTANCE; checkArgs$.invoke(args); }
我們得到的是一個不完整的代碼,這時候需要我們前往項目工程,結(jié)合一些對應(yīng)的class文件分析。首先我們找到類似這樣的文件MainKt$outMethodCapture$1.class(其class文件按照”文件名$方法名$內(nèi)部類序號”的規(guī)則)。
使用javap方法再次反編譯分析該文件,注意對于$符號需要簡單處理一下。
? KotlinInnerFunction javap -c "MainKt\$outMethodNonCapture\$1.class" Compiled from "Main.kt" final class MainKt$outMethodNonCapture$1 extends kotlin.jvm.internal.Lambda implements kotlin.jvm.functions.Function1<java.lang.String[], kotlin.Unit> { public static final MainKt$outMethodNonCapture$1 INSTANCE; public java.lang.Object invoke(java.lang.Object); Code: 0: aload_0 1: aload_1 2: checkcast #11 // class "[Ljava/lang/String;" 5: invokevirtual #14 // Method invoke:([Ljava/lang/String;)V 8: getstatic #20 // Field kotlin/Unit.INSTANCE:Lkotlin/Unit; 11: areturn public final void invoke(java.lang.String[]); Code: 0: aload_1 1: ldc #23 // String args 3: invokestatic #29 // Method kotlin/jvm/internal/Intrinsics.checkParameterIsNotNull:(Ljava/lang/Object;Ljava/lang/String;)V 6: aload_1 7: checkcast #31 // class "[Ljava/lang/Object;" 10: astore_2 11: aload_2 12: arraylength 13: ifne 20 16: iconst_1 17: goto 21 20: iconst_0 21: ifeq 44 24: ldc #33 // String outMethodNonCapture check args 26: astore_2 27: getstatic #39 // Field java/lang/System.out:Ljava/io/PrintStream; 30: aload_2 31: invokevirtual #45 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V 34: new #47 // class java/lang/Throwable 37: dup 38: invokespecial #51 // Method java/lang/Throwable."<init>":()V 41: invokevirtual #54 // Method java/lang/Throwable.printStackTrace:()V 44: return MainKt$outMethodNonCapture$1(); Code: 0: aload_0 1: iconst_1 2: invokespecial #61 // Method kotlin/jvm/internal/Lambda."<init>":(I)V 5: return static {}; Code: 0: new #2 // class MainKt$outMethodNonCapture$1 3: dup 4: invokespecial #80 // Method "<init>":()V 7: putstatic #82 // Field INSTANCE:LMainKt$outMethodNonCapture$1; 10: return }
上面的類其實比較簡單,更重要的這是一個單例的實現(xiàn)。因為這樣相比捕獲的情況下,減少了匿名內(nèi)部類的生成和實例的創(chuàng)建,理論上帶來的代價也會更小。
考慮到上面的對比,如果在使用局部方法時,建議使用不捕獲外部變量的方式會更加推薦。
使用注意
是的,使用局部方法有一個注意事項,也就是一種規(guī)則約定,那就是需要先定義才能使用,否則會報錯,如下所示
fun outMethodInvalidCase(args: Array<String>) { checkArgs()//invalid unresolved reference fun checkArgs() { if (args.isEmpty()) { println("innerMethod check args") Throwable().printStackTrace() } } checkArgs()//valid }
但是呢,先定義局部方法,再使用還是有一些問題,這種問題主要表現(xiàn)在代碼可讀性上。
試想一下,如果你進入一個方法,看到的是一連串的局部方法,可能或多或少有點別扭。
但是試想一下,既然有這樣的問題,為什么還要被設(shè)計成這個樣子呢。首先,我們先看個小例子
0fun outMethodInvalidCase(args: Array<String>) { checkArgs(args) var a = 0 //the reason why it's unresolved fun checkArgs(args: Array<String>) { if (args.isEmpty()) { println("outMethodNonCapture check args") Throwable().printStackTrace() a.toString() } } }
看完上述內(nèi)容,你們掌握如何在Kotlin中使用局部方法的方法了嗎?如果還想學到更多技能或想了解更多相關(guān)內(nèi)容,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝各位的閱讀!
網(wǎng)頁名稱:如何在Kotlin中使用局部方法-創(chuàng)新互聯(lián)
標題來源:http://bm7419.com/article48/ceocep.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供外貿(mào)建站、網(wǎng)站制作、自適應(yīng)網(wǎng)站、網(wǎng)頁設(shè)計公司、做網(wǎng)站、全網(wǎng)營銷推廣
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容