b2科目四模拟试题多少题驾考考爆了怎么补救
b2科目四模拟试题多少题 驾考考爆了怎么补救

使用Kotlin的内联函数

电脑杂谈  发布时间:2020-03-31 21:01:58  来源:网络整理

函数递归调用一_c语言函数递归调用_函数调用 内联函数

Kotlin的内联函数kotlin的高级功能,也是与Java的区别之一;

关于Kotlin使用内联函数的原因,当然,它肯定有其好处,

调用方法实际上是推和弹出方法的过程. 调用方法时,将堆栈框架推入方法堆栈,然后执行方法主体. 方法结束后函数调用 内联函数,将堆栈框架推出堆栈. 流程是一个耗资源的流程,在此流程中传递参数也会消耗资源.

在编写代码时,我们不可避免地会遇到这种情况,即很多地方的代码是相同的,因此我们提取一个公共方法来调用,这看起来非常简洁;但是还有一个问题,就是这种方法会被频繁调用,这会消耗资源

栗子:

fun <T> method(lock: Lock, body: () -> T): T {
        lock.lock()
        try {
            return body()
        } finally {
            lock.unlock()
        }
    }

这里的方法方法在调用时不会将形式参数传递给其他方法. 叫它:

 method(lock, {"我是body的方法体"})//lock是一个Lock对象

对于编译器,要调用方法方法,必须传递参数lock和lambda表达式{“我是主体”. 您必须将方法方法从堆栈中推出. 此过程将消耗资源. 如果在很多地方调用它,它将执行多次,这将消耗大量资源.

所以我介绍了内联

标记为inline的函数是一个内联函数,其原理是: 在编译过程中,用该函数的方法主体替换调用此函数的位置

栗子:

c语言函数递归调用_函数递归调用一_函数调用 内联函数

我们称上述方法为方法

 method(lock, {"我是body方法体"})//lock是一个Lock对象

实际上,上面调用的方法会将以下内容替换为在编译过程中调用该方法的位置,这将减少将方法压入堆栈和弹出堆栈的方式,从而减少资源消耗;

        lock.lock()
        try {
            return "我是body方法体"
        } finally {
            lock.unlock()
        }

换句话说,内联关键字实际上增加了代码量,但提高了性能,并且增加的代码量是在编译时执行的,这并不影响程序的可读性,可以说非常很好.

尽管内联非常有用,但是会出现内联函数的参数(ps: 参数是函数,例如上面的body函数)的问题. 呼叫,它将报告错误.

栗子:

inline fun <T> mehtod(lock: Lock, body: () -> T): T {
            lock.lock()
            try {
                otherMehtod(body)//会报错
                return body()
            } finally {
                lock.unlock()
            }
    }
    fun <T> otherMehtod(body: ()-> T){
    }

原因: 由于method是内联函数,因此它的形式参数也是内联的,因此body是内联的,但是在编译时,body不再是函数对象,而是特定的值,但其他方法必须接收主体函数对象,因此将无法编译.

解决方案: 当然,添加noinline,其效果已经非常明显. 这是为了使内联函数的参数函数不内联,并保留原始函数特征.

特定操作:

fun main(args: Array<String>) {
    val lock = ReentrantLock()
    mehtod(lock,{"body方法体"})
}
inline fun <T> mehtod(lock: Lock, noinline body: () -> T): T {
    lock.lock()
    try {
        otherMehtod(body)
        return body()
    } finally {
        lock.unlock()
    }
}
fun <T> otherMehtod(body: ()-> T){
}

c语言函数递归调用_函数递归调用一_函数调用 内联函数

在编译过程中不会内联此主体函数

看反编译

   public static final void main(@NotNull String[] args) {
      Intrinsics.checkParameterIsNotNull(args, "args");
      ReentrantLock lock = new ReentrantLock();
      //这里是生成了一个函数对象
      Function0 body$iv = (Function0)null.INSTANCE;
      ((Lock)lock).lock();
      try {
         otherMehtod(body$iv);
         Object var3 = body$iv.invoke();
      } finally {
         ((Lock)lock).unlock();
      }
   }
   public static final Object mehtod(@NotNull Lock lock, @NotNull Function0 body) {
      Intrinsics.checkParameterIsNotNull(lock, "lock");
      Intrinsics.checkParameterIsNotNull(body, "body");
      lock.lock();
      Object var3;
      try {
         otherMehtod(body);
         var3 = body.invoke();
      } finally {
         InlineMarker.finallyStart(1);
         lock.unlock();
         InlineMarker.finallyEnd(1);
      }
      return var3;
   }
   public static final void otherMehtod(@NotNull Function0 body) {
      Intrinsics.checkParameterIsNotNull(body, "body");
   }

什么是交叉内联? crossinline的作用是允许在内联函数中将标记为crossinline的lambda表达式允许非本地返回.

您如何理解?

首先,让我们看一下非本地收益.

我们都知道,在kotlin中,如果函数中存在lambda表达式,则lambda不支持直接通过return @ XXXinterface直接通过return退出函数.

栗子:

fun outterFun() {
    innerFun {
        //return  //错误,不支持直接return
        //只支持通过标签,返回innerFun
        return@innerFun 1
    }
    //如果是匿名或者具名函数,则支持
    var f = fun(){
        return
    }
}
fun innerFun(a: () -> Int) {}

但是这个函数是内联的没关系

fun outterFun() {
    innerFun {
        return  //支持直接返回outterFun       
    }
}
inline fun innerFun(a: () -> Int) {}

这种直接从lambda返回函数的方法是非本地返回.

c语言函数递归调用_函数调用 内联函数_函数递归调用一

crossinline是为了防止它直接返回

栗子

fun outterFun() {
    innerFun {
        return  //这样就报错了
    }
}
inline fun innerFun( crossinline a: () -> Int) {}

这里的a函数是通过crossinline修改的,如果直接在lambda中返回,它将不会编译并传递;

官方解释:

一些内联函数可能调用传给它们的不是直接来自函数体、而是来自另一个执行上下文的 lambda 表达式参数,
例如来自局部对象或嵌套函数。在这种情况下,该 lambda 表达式中也不允许非局部控制流。为了标识这种情况
,该 lambda 表达式参数需要用 crossinline 修饰符标记。

简而言之,如果我们直接在lambda参数中结束当前函数而不给lambda提供返回值,则不允许这种情况.

当然,使用此功能的机会并不多,但有时仍会使用.

栗子:

在此处编写代码段:

fun main(args: Array<String>) {
    //正常
    method{
        1
    }
    //return报错
    method{
        return 
    }
}
interface TestInter{
    fun test(a:Int):Int
}
inline fun method(crossinline t: (Int) -> Int): TestInter = object : TestInter {
    override fun test(a: Int): Int = t.invoke(a)
}

如果未通过交叉内联禁止lambda表达式t的返回操作,则直接返回后t的返回值为Unit,这不符合fun test的要求(a: Int): Int需要Int返回值,刚返回一个不符合要求的单位.

函数调用 内联函数_c语言函数递归调用_函数递归调用一

从字面上看,具体化是什么: 实际是泛型的化;

我们都知道,如果您在Java中使用泛型,则不能直接使用泛型类型,但是可以使用kotlin,这与Java显着不同.

java中通常的解决方案是通过函数传递类

但是kotlin很老,可以直接使用. 主要是内联函数inline函数调用 内联函数,它允许kotlin通过泛型直接获取泛型类型.

栗子:

 inline fun <reified T : Activity> Activity.startActivity() {
     startActivity(Intent(this, T::class.java))
}

编写一种通过Kotlin扩展名启动活动的方法,只需传入活动的通用类型即可.

startActivity<MainActivity>()

简单又酷吗?

让我们再次看一看需求,有时我们需要创建一个Fragment实例并传递参数. 如果是以前的版本,则可以在每个片段中写上:

 fun newInstance(param: Int): ActyFragment {
            val fragment = ActyFragment()
            val args = Bundle()
            args.putInt(PARAMS, param)
            fragment.arguments = args
            return fragment
        }

但这不是很低,只要需要Fragment,请将其写下来,OCD的人就受不了.

现在已通过优化进行优化

inline fun <reified F : Fragment> Context.newFragment(vararg args: Pair<String, String>): F {
    val bundle = Bundle()
    args.let {
        for (arg in args) {
            bundle.putString(arg.first, arg.second)
        }
    }
    return Fragment.instantiate(this, F::class.java.name, bundle) as F
}

这样,不必为每个片段编写一个方法,可以说非常好.


本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-159254-1.html

    相关阅读
      发表评论  请自觉遵守互联网相关的政策法规,严禁发布、暴力、反动的言论

      热点图片
      拼命载入中...