I had 2 functions that does basically the same thing, so I thought to create an extension function.
The problem is that I need to extract the data of each class in order to get the correct result, I thought of creating a Generic function, and inside this function decide which class member to access inside when statement.
But when I try to call T inside the when statement, I'm getting Type parameter 'T' is not an expression
What am I doing wrong?
My function:
fun <T: Any> List<T>.extractWithSepreation(errorString: String): String {
var errorString = "There is no available $errorString"
if (this.isEmpty()) {
return errorString
}
errorString = ""
this.forEachIndexed { index, item ->
when(T)
}
}
The error message pretty much says it all. T is not an expression, so it cannot be used inside when(...). T just refers to the class of the item of the List.
Didn't you mean using something like:
when(item) {
is ClassA -> doSomething()
is ClassB -> doSomethingElse()
}
?
Related
I don't know how to RETURN variable from the following function.
Here is the code...
downloadData.setOnClickListener {
val handler = Handler(Looper.getMainLooper())
handler.post {
val fetchData =
FetchData("http://localhost/xampp/CRM/PHP/show_contacts_db.php")
if (fetchData.startFetch()) {
if (fetchData.onComplete()) {
val result = fetchData.data.toString()
Log.i("FetchData", result)
val companyName = result.substringAfter("Name: ").substringBefore(";")
showContactName.text = "${companyName}"
val companyNumber = result.substringAfter("Number: ").substringBefore(";")
showContactNumber.text = "${companyNumber}"
}
}
}
}
companyName and companyNumber needed to be returned so I can use it in other places.
When I Try to use Return companyNumber I have a message that "return" is not allowed here.
Generally with lambdas, you don't explicitly return a value - the lambda returns the value of the last expression. Using your code as an example (it won't actually work but we'll get to that!):
handler.post {
...
companyNumber
}
which is the same as how things like map calls take a transformation function
listOf(1, 2, 3).map { it * 2 }
that's just doubling each number, but the result is being implicitly returned and stored in the resulting list, right? And it lets you chain lambdas together, since each one evaluates to a value (which might be Unit if it "doesn't return a result")
If you want, you can explicitly use what's called a qualified return:
handler.post {
...
return#post companyNumber
}
where you're naming the function call you're returning to.
Kotlin docs: returning a value from a lambda expression
Also if you want to return two values, you can't do that - so you'll have to bundle them up in a single object. You could just return a Pair, or create a data class that's more readable:
return#post Pair(companyName, companyNumber)
//or
data class CompanyDeets(val name: String, val number: String)
...
return#post CompanyDeets(companyName, companyNumber)
But aside from how you do it in general, why do you want to return anything here? Handler#post takes a Runnable which returns nothing (void in Java), and View.OnClickListener#onClick doesn't return anything either.
Neither of them would do anything with a value you returned - and if you explicitly return a value, that means your lambda's signature doesn't match (right now it's implicitly returning Unit to match what's expected by the caller), and you'll get an error
What you probably want to do instead, is create a function inside your class (Activity or whatever) that uses your data, something like fun doSomethingWith(companyName: String, companyNumber: String) and call that inside your lambda. That's way you're executing code in reaction to a click
just declare var Company Name in global, or create a function with that params
var companyName: String? = null
handler.post {
...
companyName = result.substringAfter("Name: ").substringBefore(";")
}
OR
handler.post {
...
save(result.substringAfter("Name: ").substringBefore(";"))
}
fun save(companyName: String){ ... }
Learning Functional Programming in Kotlin, I've run into some problems in understanding
fun exampleFunction(name : String, paramFun : (String) -> Unit){
...some body code...
}
When I declare such function, as seen above, function is taking 2 parameters - String type 'name' and function type 'paramFun'.
how can paramFun, which is a function and passed as an input for exampleFunction, use name (which is parameter for exampleleFunction) as its parameter
like
fun exampleFunction(name : String, paramFun : (String) -> Unit){
paramFun(name)
}
When you call a function in a function or whatever, try to remember that the fcuntion you call (paramFun(name)), is just a copy of that same function inside exempleFunction.
So basically, when you call exampleFunction, you have 2 variable you can use inside this function, after that, when you call paramFun(name), you can use name inside as you want.
When you call a function with parameter, you can use theses parameter as many time as you want in any order you want.
Ex : This is the same thing as this.
fun functionOne(a: Int, b: Int) {
a = b //or// b = a
}
the function paramFun is the same parameter as a or b , but it's a function
I'm not entirely sure I understood your problem, because you already accomplished what you seem to have trouble with:
fun exampleFunction(name : String, paramFun : (String) -> Unit){
paramFun(name)
}
If your problem is at the call site, here is how you would call exampleFunction:
exampleFunction(name = "the name param") { someParam ->
// do what you want with someParam here
}
With this call, someParam in the lambda would get the value provided as name parameter to exampleFunction, because the body of exampleFunction actually passes name as argument to the lambda when doing paramFun(name) (just like a regular function call).
I am trying to write a function in kotlin but I am not able reassign value to function parameters ,its saying val cannot be reassigned .
class WebView{
var homepage = "https://example.com"
fun webViewLoad(url: String, preferredOrientation: String) {
if (url.equals("homepage")){
url = homepage
}
}
}
when I am trying to assign a value to url = homepage .it is giving me error val cannot be reassigned , I am new to kotlin ,I do not understand what is the issue , little help will be appreciated.
Function parameters works like val variables that couldn't be reassigned. Here you need to add variable with conditional initialization:
fun webViewLoad(url: String, preferredOrientation: String) {
val urlValue = if (url.equals("homepage")){
homepage
} else {
url
}
... //use here "urlValue" variable
}
By the way, in kotlin you don't need to use equals function to compare string: common operator == will be automatically replaced with equals in byte code.
Kotlin parameters are immutable since Kotlin M5.1
(Reference)
The main reason is that this was confusing: people tend to think that this means passing a parameter by reference, which we do not support (it is costly at runtime). Another source of confusion is primary constructors: “val” or “var” in a constructor declaration means something different from the same thing if a function declarations (namely, it creates a property). Also, we all know that mutating parameters is no good style, so writing “val” or “var” infront of a parameter in a function, catch block of for-loop is no longer allowed.
It is giving you error "val cannot be reassigned" because Kotlin function parameters are immutable i.e "val" by default. You don't need to mention the "val" keyword for it.
Quick Solution would be:
class WebView{
var homepage = "https://example.com"
fun webViewLoad(url: String, preferredOrientation: String) {
val finalUrl = if (url.equals("homepage")) homepage else url
}
}
Kotlin function parameters are final. There is no val or final keyword because that's the default (and can't be changed). Have a look at this.
By default parameters passed in the function are final what you can do is to add var. Hope it helps.
fun webViewLoad(var url: String, preferredOrientation: String) {
if (url.equals("homepage")){
url = homepage
}
}
I get to know about the Invoke operator that,
a() is equivalent to a.invoke()
Is there anything more regarding Invoke operator than please explain. Also, I did not get any example of Invoke operator overloading.
Is Invoke operator overloading possible? If possible then can anyone please explain about the Invoke operator overloading with an example? I did not get anything regarding this.
Thanks in advance.
Yes, you can overload invoke. Here's an example:
class Greeter(val greeting: String) {
operator fun invoke(target: String) = println("$greeting $target!")
}
val hello = Greeter("Hello")
hello("world") // Prints "Hello world!"
In addition to what #holi-java said, overriding invoke is useful for any class where there is a clear action, optionally taking parameters. It's also great as an extension function to Java library classes with such a method.
For example, say you have the following Java class
public class ThingParser {
public Thing parse(File file) {
// Parse the file
}
}
You can then define an extension on ThingParser from Kotlin like so:
operator fun ThingParser.invoke(file: File) = parse(file)
And use it like so
val parser = ThingParser()
val file = File("path/to/file")
val thing = parser(file) // Calls ThingParser.invoke extension function
The most way to use a invoke operator is use it as a Factory Method, for example:
// v--- call the invoke(String) operator
val data1 = Data("1")
// v--- call the invoke() operator
val default = Data()
// v-- call the constructor
val data2 = Data(2)
This is because the companion object is a special object in Kotlin. Indeed, the code Data("1") above is translated to the code as below:
val factory:Data.Companion = Data
// v-- the invoke operator is used here
val data1:Data = factory.invoke("1")
class Data(val value: Int) {
companion object {
const val DEFAULT =-1
// v--- factory method
operator fun invoke(value: String): Data = Data(value.toInt())
// v--- overloading invoke operator
operator fun invoke(): Data = Data(DEFAULT)
}
}
Operator Function invoke()
Kotlin provides an interesting function called invoke, which is an operator function. Specifying an invoke operator on a class allows it to be called on any instances of the class without a method name.
Let’s see this in action:
class Greeter(val greeting: String) {
operator fun invoke(name: String) {
println("$greeting $name")
}
}
fun main(args: Array<String>) {
val greeter = Greeter(greeting = "Welcome")
greeter(name = "Kotlin")
//this calls the invoke function which takes String as a parameter
}
A few things to note about invoke() here. It:
Is an operator function.
Can take parameters.
Can be overloaded.
Is being called on the instance of a Greeter class without method name.
In addition to the other answers:
It's possible to define a class extending an anonymous function.
class SpecialFunction : () -> Unit {}
In such case, the operator invoke is already defined, so it needs to be overriden:
class MyFunction : () -> Unit {
override fun invoke() { println("Hi Mom") }
}
One more thing about syntax repercussions:
If such "functor" is called right after constructing it, you end up with double parentheses:
MyFunction()()
And, if such functor returns another functor, you may see some obscurities like
MyFunction()()()()()...
perhaps including parameters. This will not surprise anyone coming from the JavaScript world, though.
If you have some Python background,
you can think invoke in Kotlin as __call__ in Python.
By using this, you can "call" your object as if it's a function.
One difference is: you can overload invoke, but there is no official way to overload methods in Python.
I've been writing in Kotlin for a while, and I get used to use next pattern:
variable.addSomething(object: TargetType() { ...code... })
or
var variable = object: TargetType() { ...code... }
(if i'm not missing something)
Is it possible to somehow use this pattern in Swift ? And how is it called ? :)
Edit:
What I actually want to do - to store preconfigured RxSwift.SingleEvent in a let / var inside object and reuse it later multiple times.
In code, as I imagine, it should look like that:
private var observer = SingleEvent<Response>(ok_callback, error_callback) {
override success(el: Element) {
ok_callback(el)
super.success(el)
}
override error(er: Error) {
self.onErrorRetry(er, callback)
}
}
And if retry after some magic works - simply call my callback and return back :)
Its seems to be trailing closure. Adapted from Swift programming language - Closures:
If you need to pass a closure expression to a function as the
function’s final argument and the closure expression is long, it can
be useful to write it as a trailing closure instead. A trailing
closure is written after the function call’s parentheses, even though
it is still an argument to the function. When you use the trailing
closure syntax, you don’t write the argument label for the closure as
part of the function call.
Let's code it:
Simply, all you have to do is just to create a function which its last argument is a closure:
func doSomething(firstParameter: Any, closure: () -> Void) { }
thus you could call it as:
doSomething(firstParameter: "whatever") {
// ...
}
Nothing special goes here, it is a cool feature from the Swift language to "trail" closure parameter if its the last one in the function signature.
In case of initialization, it is almost the same:
struct MyObject {
init(firstParameter: Any, closure: () -> Void) { }
}
let variable = MyObject(firstParameter: "whatever") { }
Certainly, this pattern is followed by many other functions in the language, but here is an example of the merge method for the Dictionary, you could recognize how you could type it in more than one way as mentioned in the answers of: Map Dictionary Keys to add values - Swift.
Update:
If you are aiming to use it as constant/variable -to be passed for a function for example-, you could do it like this:
let variable: (String) -> Void = { name in
print("The name is: \(name)!")
}
At this point, variable type is (String) -> Void which means that its a constant that could be passed somewhere else; Consider the following method:
func doSomething(closure: (String) -> Void) {
closure("Nikita")
}
Because doSomething takes a parameter of type (String) -> Void, you could do:
doSomething(closure: variable) // The name is: Nikita!
instead of calling it as:
doSomething { name in
print("The name is: \(name)!")
}
which prevents the boilerplate code.