如何在Kotlin中使用局部方法-創(chuàng)新互聯(lián)

如何在Kotlin中使用局部方法?相信很多沒(méi)有經(jīng)驗(yàn)的人對(duì)此束手無(wú)策,為此本文總結(jié)了問(wèn)題出現(xiàn)的原因和解決方法,通過(guò)這篇文章希望你能解決這個(gè)問(wèn)題。

成都創(chuàng)新互聯(lián)公司長(zhǎng)期為上千多家客戶提供的網(wǎng)站建設(shè)服務(wù),團(tuán)隊(duì)從業(yè)經(jīng)驗(yàn)10年,關(guān)注不同地域、不同群體,并針對(duì)不同對(duì)象提供差異化的產(chǎn)品和服務(wù);打造開(kāi)放共贏平臺(tái),與合作伙伴共同營(yíng)造健康的互聯(lián)網(wǎng)生態(tài)環(huán)境。為府谷企業(yè)提供專業(yè)的成都網(wǎng)站設(shè)計(jì)、成都做網(wǎng)站,府谷網(wǎng)站改版等技術(shù)服務(wù)。擁有10余年豐富建站經(jīng)驗(yàn)和眾多成功案例,為您定制開(kāi)發(fā)。

在Kotlin中,定義方法很有趣,不僅僅因?yàn)榉椒ǖ年P(guān)鍵字是fun(function前幾個(gè)字符),還是因?yàn)槟銜?huì)驚奇的發(fā)現(xiàn),它允許我們?cè)诜椒ㄖ卸x方法。如下

fun methodA() {
 fun methodB() {

 }
 methodB() //valid
}

//methodB() invalid

其中

  • methodB定義在methodA的方法體中,即methodB被稱為局部方法或局部函數(shù)

  • methodB只能在methodA中方法調(diào)用

  • methodB在methodA方法外調(diào)用,會(huì)引起編譯錯(cuò)誤

既然Kotlin支持了局部方法,相比它應(yīng)該有什么特殊的用武之地呢

首先它的特點(diǎn)還是像它的名字一樣,局部,這就意味著它有著無(wú)可比擬的更小范圍的限定能力。保證了小范圍的可用性,隔絕了潛在的不相關(guān)調(diào)用的可能。

作為編程中的金科玉律,方法越小越好,相比縱向冗長(zhǎng)的代碼片段,將其按照職責(zé)切分成功能單一的小的局部方法,最后組織起來(lái)調(diào)用,會(huì)讓我們的代碼顯得更加的有條理和清晰。

作為一個(gè)程序員,好奇應(yīng)該是他的特質(zhì)之一,我們應(yīng)該會(huì)想要研究一下,局部方法的實(shí)現(xiàn)原理是什么,至少我們?cè)贘ava時(shí)代從來(lái)沒(méi)有見(jiàn)過(guò)這種概念。

其實(shí)這件事仔細(xì)研究起來(lái),還是有不少細(xì)節(jié)的。因?yàn)檫@其中局部方法可以捕獲外部的變量也可以不捕獲外部的變量。

下面就是捕獲外部變量的一種情況

fun outMethodCapture(args: Array<String>) {
 fun checkArgs() {
 if (args.isEmpty()) {
  println("innerMethod check args")
  Throwable().printStackTrace()
 }
 }
 checkArgs()
}

這其中,局部方法checkArgs捕獲了outMethodCapture的參數(shù)args。

所以,不捕獲外部變量的情況也不難理解,如下,即checkArgs處理args都是通過(guò)參數(shù)傳遞的。

fun outMethodNonCapture(args: Array<String>) {
 fun checkArgs(args: Array<String>) {
 if (args.isEmpty()) {
  println("outMethodNonCapture check args")
  Throwable().printStackTrace()
 }
 }
 checkArgs(args)
}

首先我們分析一下捕獲變量的局部方法的實(shí)現(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();
}

如上實(shí)現(xiàn)原理,就是局部方法實(shí)現(xiàn)其實(shí)就是實(shí)現(xiàn)了一個(gè)匿名內(nèi)部類的實(shí)例,然后再次調(diào)用即可。 對(duì)于不捕獲的局部方法要稍有不同,首先我們反編譯得到對(duì)應(yīng)的Java代碼

public static final void outMethodNonCapture(@NotNull String[] args) {
 Intrinsics.checkParameterIsNotNull(args, "args");
 <undefinedtype> checkArgs$ = null.INSTANCE;
 checkArgs$.invoke(args);
}

我們得到的是一個(gè)不完整的代碼,這時(shí)候需要我們前往項(xiàng)目工程,結(jié)合一些對(duì)應(yīng)的class文件分析。首先我們找到類似這樣的文件MainKt$outMethodCapture$1.class(其class文件按照”文件名$方法名$內(nèi)部類序號(hào)”的規(guī)則)。

使用javap方法再次反編譯分析該文件,注意對(duì)于$符號(hào)需要簡(jiǎn)單處理一下。

? 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
}

上面的類其實(shí)比較簡(jiǎn)單,更重要的這是一個(gè)單例的實(shí)現(xiàn)。因?yàn)檫@樣相比捕獲的情況下,減少了匿名內(nèi)部類的生成和實(shí)例的創(chuàng)建,理論上帶來(lái)的代價(jià)也會(huì)更小。

考慮到上面的對(duì)比,如果在使用局部方法時(shí),建議使用不捕獲外部變量的方式會(huì)更加推薦。

使用注意

是的,使用局部方法有一個(gè)注意事項(xiàng),也就是一種規(guī)則約定,那就是需要先定義才能使用,否則會(huì)報(bào)錯(cuò),如下所示

fun outMethodInvalidCase(args: Array<String>) {
 checkArgs()//invalid unresolved reference
 fun checkArgs() {
  if (args.isEmpty()) {
   println("innerMethod check args")
   Throwable().printStackTrace()
  }
 }
 checkArgs()//valid
}

但是呢,先定義局部方法,再使用還是有一些問(wèn)題,這種問(wèn)題主要表現(xiàn)在代碼可讀性上。

試想一下,如果你進(jìn)入一個(gè)方法,看到的是一連串的局部方法,可能或多或少有點(diǎn)別扭。

但是試想一下,既然有這樣的問(wèn)題,為什么還要被設(shè)計(jì)成這個(gè)樣子呢。首先,我們先看個(gè)小例子

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中使用局部方法的方法了嗎?如果還想學(xué)到更多技能或想了解更多相關(guān)內(nèi)容,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝各位的閱讀!

網(wǎng)頁(yè)名稱:如何在Kotlin中使用局部方法-創(chuàng)新互聯(lián)
標(biāo)題來(lái)源:http://muchs.cn/article48/ceocep.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供外貿(mào)建站、網(wǎng)站制作自適應(yīng)網(wǎng)站、網(wǎng)頁(yè)設(shè)計(jì)公司、做網(wǎng)站、全網(wǎng)營(yíng)銷推廣

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

成都app開(kāi)發(fā)公司