Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/kotlin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
什么时候应该选择Kotlin扩展函数?_Kotlin_Code Structure - Fatal编程技术网

什么时候应该选择Kotlin扩展函数?

什么时候应该选择Kotlin扩展函数?,kotlin,code-structure,Kotlin,Code Structure,在Kotlin中,至少有一个参数的函数可以定义为常规的非成员函数,也可以定义为一个参数为接收者的函数 至于作用域,似乎没有什么区别:两者都可以在类和其他函数的内部或外部声明,并且都可以或不可以具有相同的可见性修饰符 语言参考似乎不建议在不同的情况下使用常规函数或扩展函数 所以,我的问题是:什么时候扩展函数比常规的非成员函数更有优势?什么时候常规函数比扩展函数更有优势 foo.bar(baz,baq)vsbar(foo,baz,baq) 这仅仅是函数语义的一个暗示(接收者绝对是焦点),还是在使用扩

在Kotlin中,至少有一个参数的函数可以定义为常规的非成员函数,也可以定义为一个参数为接收者的函数

至于作用域,似乎没有什么区别:两者都可以在类和其他函数的内部或外部声明,并且都可以或不可以具有相同的可见性修饰符

语言参考似乎不建议在不同的情况下使用常规函数或扩展函数

所以,我的问题是:什么时候扩展函数比常规的非成员函数更有优势?什么时候常规函数比扩展函数更有优势

foo.bar(baz,baq)
vs
bar(foo,baz,baq)


这仅仅是函数语义的一个暗示(接收者绝对是焦点),还是在使用扩展函数时会使代码更干净或打开机会?

至少有一种情况是扩展函数是必须调用的链接,也称为“流畅风格”:

假设您希望使用自己的操作从Java8扩展流接口。当然,您可以使用普通函数来实现这一点,但它看起来非常丑陋:

doZ(doY(doX(someStream())))
显然,您希望为此使用扩展函数。 此外,不能将普通函数设为中缀,但可以使用扩展函数:

infix fun <A, B, C> ((A) -> B).`|`(f: (B) -> C): (A) -> C = { a -> f(this(a)) }

@Test
fun pipe() {
    val mul2 = { x: Int -> x * 2 }
    val add1 = { x: Int -> x + 1 }
    assertEquals("7", (mul2 `|` add1 `|` Any::toString)(3))
}
infixfun((A)->B)。```(f:(B)->C:(A)->C={A->f(this(A))}
@试验
风笛{
val mul2={x:Int->x*2}
val add1={x:Int->x+1}
assertEquals(“7”,(mul2``add1``Any::toString)(3))
}

扩展功能与安全呼叫操作员配合得非常好。。如果您希望函数的参数有时为
null
,而不是提前返回,请将其设置为扩展函数的接收者

普通功能:

fun nullableSubstring(s: String?, from: Int, to: Int): String? {
    if (s == null) {
        return null
    }

    return s.substring(from, to)
}
fun String.extensionSubstring(from: Int, to: Int) = substring(from, to)
扩展功能:

fun nullableSubstring(s: String?, from: Int, to: Int): String? {
    if (s == null) {
        return null
    }

    return s.substring(from, to)
}
fun String.extensionSubstring(from: Int, to: Int) = substring(from, to)
呼叫地点:

fun main(args: Array<String>) {
    val s: String? = null

    val maybeSubstring = nullableSubstring(s, 0, 1)
    val alsoMaybeSubstring = s?.extensionSubstring(0, 1)
fun main(args:Array){
val s:字符串?=null
val-maybeSubstring=nullableSubstring(s,0,1)
val alsoMaybeSubstring=s?.extensionSubstring(0,1)

正如您所看到的,两者都做相同的事情,但是扩展函数较短,并且在调用站点上,很明显结果是可以为空的。

扩展函数在某些情况下很有用,在其他情况下是必需的:

惯用格:

  • 当您想要增强、扩展或更改现有API时。扩展函数是通过添加新功能来更改类的惯用方法。您可以添加和。请参阅中的示例,以向
    ObjectMapper
    类添加方法,从而简化
    TypeReference
    和泛型的处理

  • 向不能在
    null
    上调用的新方法或现有方法添加null安全性。例如
    String?的String的扩展函数。isNullOrBlank()
    允许您在
    null
    字符串上使用该函数,而无需先执行自己的
    null
    检查。函数本身在调用内部函数之前进行检查。请参阅

  • 强制案例:

  • 当您希望为接口使用内联默认函数时,必须使用扩展函数将其添加到接口中,因为您不能在接口声明中这样做(内联函数必须是
    final
    ,这在接口中当前是不允许的)。这在需要内联具体化函数时非常有用

  • 当您想要为(集合中的项){…}添加
    支持时,当前不支持该用法。您可以添加一个
    iterator()
    扩展方法,该方法遵循中描述的规则--即使返回的类似迭代器的对象也可以使用扩展来满足提供
    next()的规则
    hasNext()

  • 将运算符添加到现有类中,如
    +
    *
    (1的专门化,但不能以任何其他方式进行,因此是必需的)。请参阅

  • 可选案例:

  • 您希望控制调用方可以看到某个对象时的作用域,因此只能在允许调用可见的上下文中扩展类。这是可选的,因为您可以始终允许看到扩展

  • 您有一个界面,您希望简化所需的实现,同时仍然允许用户使用更简单的帮助函数。您可以选择为该界面添加默认方法以提供帮助,或使用扩展函数添加界面的非预期实现部分。一个允许覆盖默认值,另一个是其他则没有(扩展与成员的优先级除外)

  • 当您希望将函数与一类功能关联时,扩展函数使用其receiver类作为查找它们的位置。它们的名称空间将成为类(或多个类)而顶级函数将更难找到,并且将填充IDE代码完成对话框中的全局名称空间。您还可以修复现有的库名称空间问题。例如,在Java 7中,您有
    Path
    类,很难找到
    文件。exist(Path)
    方法,因为它的名称间隔很奇怪。该函数可以直接放在
    路径。exists()上。(@kirill)

  • 优先规则:

    扩展现有类时,请记住优先级规则。它们在中描述为:

    对于当前上下文中的每个隐式接收者,我们尝试成员,然后是局部扩展函数(也包括具有扩展函数类型的参数),然后是非局部扩展


    在某些情况下,您必须使用扩展方法。例如,如果您有一些列表实现
    MyList
    ,您可以编写一个扩展方法,如