How to call extension methods outside the class in which they are defined?

Here is a minimal example demonstrating the problem:

abstract class Base { abstract fun String.extension(x: Char) } class Derived : Base() { override fun String.extension(x: Char) { // Calling lots of methods on String, hence extension method println("${first()} $length ${last()} ${firstOrNull { it == x }} ...") } } 

Invoking an extension method from Java is trivial:

 Base o = new Derived(); o.extension("hello world", 'l'); 

But I can’t understand how to do this in pure Kotlin. Neither String nor Base has an extension method.

+5
source share
3 answers

First, note that the extension function, defined as a member, requires two receivers, one is an instance of the wrapper class (the dispatcher-receiver, usually this enclosing class), and the other is an instance of the type the function extends (extension receiver). This is described here .

So, to call such a function from outside the class, you must provide two receivers. Kotlin has no syntax to do this explicitly as (x, "abc").stringExtension() , but you can provide a dispatch manager implicitly using the lambda extension :

 class C(val name: String) { fun String.extended() = this + " extended by " + name } fun main(args: Array<String>) { val c = C("c") with(c) { println("abc".extended()) } } 

(runnable demo of this code)

In the with(...) { ... } block with(...) { ... } c becomes an implicit receiver, which allows you to use it as a receiver for sending member extensions to c . This will work with any other function that uses function types with receivers: apply , run , use , etc.

In your case, it will be with(o) { "hello world".extension('l') }

As @KirillRakhman noted, an extension receiver of an extension function for c can also be implicitly used as a send receiver for extensions defined inside c

 fun C.someExtension() = "something".extended() 
+8
source

Your extension function is defined only inside the Base / Derived class. See Declaring Extensions as Members .

 abstract class Base { abstract fun String.extension(x: Char) } class Derived : Base() { override fun String.extension(x: Char) { // Calling lots of methods on String, hence extension method println("${first()} $length ${last()} ${firstOrNull { it == x }} ...") } fun callExtension(c: Char) { "hello".extension(c) } } fun main(args: Array<String>) { val base = Derived() base.callExtension('h') } 
0
source

To decrypt the extension method outside the class using it, you must NOT implement it inside the class, and you must do like this:

 package com.sample.test import java.io.File fun File.folderLength() : Long { return 0L } 

So, in your class that calls this method:

 package com.sample.util import com.sample.test.* import java.io.File class foo{ fun getFolderSize(url: String) : Long{ var file = new File("...") var length = file.folderLength() return length } } 

Hope this helps you.

0
source

Source: https://habr.com/ru/post/1265348/


All Articles