将内联关键字用于Kotlin中的小型私有函数?

aag*_*pow 3 readability inline kotlin

我想知道,内联小型私有函数是否是一个好主意?就我而言,这些函数仅出于可读性目的而存在,而且我知道,它们仅被调用过几次,因此较大的字节码大小无关紧要。
我知道,性能提升也可能是微不足道的,因为我没有传递函数类型(编译器实际上警告我),但是让我们假设它是我们应用程序中的热点。

实际示例:

我有一个理论上无限的符号带(像图灵机一样),它由两个阵列(分别是位置<0和位置> = 0的左侧和右侧)建模。现在,我已经进行了许多读写操作,这些操作被假定为很多东西。

在Java中,我有:

/**
 * @param cell the cell
 * @return the symbol at the specified cell
 */
public char read(int cell) {
    char[] tape;
    if (cell < 0) {
        tape = left;
        cell = -cell - 1;
    } else {
        tape = right;
    }
    return cell < tape.length ? tape[cell] : blank;
}

/**
 * Writes a symbol to the specified cell.
 * @param c    the symbol
 * @param cell the cell
 */
public void write(char c, int cell) {
    char[] tape;
    if (cell < 0) {
        cell = -cell - 1;
        if (cell >= left.length) left = expandArray(left, cell, blank);
        tape = left;
    } else {
        if (cell >= right.length) right = expandArray(right, cell, blank);
        tape = right;
    }
    tape[cell] = c;
}
Run Code Online (Sandbox Code Playgroud)

现在,我想将代码片段翻译为kotlin,阅读内联函数并提出以下内容:

fun read(cell: Int = headPosition) = when {
    cell < 0 -> read(left, -cell - 1)
    else     -> read(right, cell)
}

private inline fun read(tape: CharArray, cell: Int): Char {
    return if (cell < tape.size) tape[cell] else blank
}

fun write(c: Char, cell: Int = headPosition) = when {
    cell < 0 -> left = write(c, left, -cell - 1)
    else -> right = write(c, right, cell)
}

private inline fun write(c: Char, tape: CharArray, cell: Int): CharArray = when {
    cell >= tape.size -> expandArray(tape, cell, blank)
    else -> tape
}.also { it[cell] = c }
Run Code Online (Sandbox Code Playgroud)

我个人认为,尤其是读取功能很容易阅读。
所以这是一个好主意,我可以忽略IDE的警告吗?还是我错过了什么?也许有一种最佳实践或其他模式来编写这些函数,而不必两次(几乎)重复相同的行(对于位置<0和位置> = 0)。

Jay*_*ard 6

不需要内联非常小的重复使用的函数,因为JVM JIT认为合适时仍可以为您执行此操作。如果内联函数,则确实会在生成的字节码中造成一点膨胀,但是对于未从代码中许多不同点调用的函数,也没有太大的危害。对于较大的内联函数,代码中许多地方使用的函数以及调用其他内联函数的内联函数,字节码膨胀更糟。您的案子根本不会造成太大影响。

短方法从内联中受益匪浅,正如您可以在《短方法还清:JIT内联

符合以下条件的方法可以进行内联:

  • 它很小-字节码大小小于35个字节(可以被-XX:MaxInlineSize = X标志覆盖)。
  • 它经常被调用(很热),并且小于325个字节(可以被-XX:MaxFreqInlineSize = X标志覆盖)。

如果超过了这些参数,或者要预热内联,则可以使用inline关键字使它在编译时发生。

您还希望在以下情况下inline在小型函数上使用:

  • 您想允许传递给函数的lambda进行非本地返回
  • 您要使用修饰的泛型类型参数
  • 您正在编写一个函数,该函数接受以高重复率使用的lambda,并且您希望避免对该lambda进行函数调用。通过内联此类函数,Kotlin编译器还可以内联lambda。