Kotlin 扩展 Any?.toString()

Kotlin Extension Any?.toString()

我一直在尝试在 Kotlin 中使用扩展函数。

class ExtensionExample() {

   var name: String? = null

   fun Any?.toString() : String {

       if (this == null) {
           return "Value is null"
       }

       return "Value is not null"
   }
}

当我像下面这样打印 name 变量时

println(ExtensionExample().name.toString())

它应该打印成

Value is null

但它没有像我预期的那样打印出来。它只打印 null.

有人可以解释一下吗?

Extension functions have scopes。这就是为什么在 ExtensionExample class.

之外无法访问它的原因

通常,扩展函数被定义为顶级函数。也就是说,它们往往属于 class.

之外

您的 toString 分机是在 ExtensionExample 中定义的。 This is possible,但是表示只在这个class的范围内可用,而这个class只

您的 main 方法可能是顶级函数(而不是 class 的成员),因此它无法访问此扩展函数。

只有其他成员可以访问此扩展功能:

class ExtensionExample {

    var name: String? = null

    fun Any?.toString(): String {
        return if (this == null) "Value is null" else "Value is not null"
    }

    fun foo() {
        println(name.toString())
    }

}

fun main(args: Array<String>) {
    ExtensionExample().foo()
}

打印"Value is null"

Try it online!

之所以编译通过,是因为调用的toString方法是Any?.toString method from the kotlin-stdlib。也就是说,这个方法已经存在

fun Any?.toString(): String

Returns a string representation of the object. Can be called with a null receiver, in which case it returns the string "null".

将您的扩展函数移出 class。然后,您的扩展函数将 隐藏 stdlib 的扩展,并且同一包中未显式导入 kotlin.toString 的任何调用都将使用您的函数。

这是您的代码的工作版本:

class ExtensionExample {

    var name: String? = null

}

fun Any?.toString(): String {
    return if (this == null) "Value is null" else "Value is not null"
}

fun main(args: Array<String>) {
    println(ExtensionExample().name.toString())
}

打印 "Value is null",如您所愿。

Try it online!


请注意,您不能使用扩展函数隐藏成员函数。也就是说,

class Test {

    fun a() {
        println("a")
    }

}

fun Test.a() {
    println("b")
}

...
Test().a()

将导致打印“a”。

您的 Any?.toString 工作的唯一原因(在移出 class 之后)是 Any? 没有成员 作为它不是 class,而是具有 class Any 的可空类型。已经存在的 toString 方法也是一个扩展,因此您的方法不会被任何成员隐藏。

If a class has a member function, and an extension function is defined which has the same receiver type, the same name and is applicable to given arguments, the member always wins.

您的扩展方法不能隐藏 Any (Object) class.

上的内置 toString 方法

至于在可空类型上调用 toString,此方法已在 Kotlin 运行时中:

/**
 * Returns a string representation of the object. Can be called with a null receiver, in which case
 * it returns the string "null".
 */
public fun Any?.toString(): String

另见docs关于扩展的解析。

在 class:

中定义扩展函数

如果您想在 ExtensionExample 中保留 toString() 的定义,您可以 从那里使用它:

class ExtensionExample() {
    var name: String? = null

    // uses the toString() extension function defined in ExtensionExample
    fun useToString() = name.toString()

    fun Any?.toString(): String {

        if (this == null) {
            return "inside: Value is null"
        }
        return "inside: Value is not null"
    }
}

这个

// uses the version of toString() defined in the Kotlin Standard library
println(ExtensionExample().name.toString()) 

// uses the inside version of toString()
println(ExtensionExample().useToString())

将打印

null
inside: Value is null

在 class 之外定义扩展函数:

但是如果要在外面用,就得搬到外面去:

class ExtensionExample() {
    var name: String? = null

    // uses the toString() extension function defined in ExtensionExample
    fun useToString() = name.toString()

    fun Any?.toString(): String {

        if (this == null) {
            return "inside: Value is null"
        }
        return "inside: Value is not null"
    }
}

fun Any?.toString(): String {

    if (this == null) {
        return "outside: Value is null"
    }
    return "outside: Value is not null"
}

这个

// uses the outside version of toString() which overrides the one from the Kotlin Standard library
println(ExtensionExample().name.toString())  

// uses the inside version of toString()
println(ExtensionExample().useToString())

将打印:

outside: Value is null
inside: Value is null