I am learning kotlin and I was reading about constructors: primary and secondary.
Here is my question that how should I access primary constructor parameters inside a secondary constructor. I am unable to access but I am not sure why? Why I am not able to access it directly?
If anyone knows please help me understand this concept in a better way. Why I am not able to access it?
I have created one demo class with two constructors here is my code:
fun main(args: Array<String>) {
val person1 = Person("Joe", 25)
println("First Name = ${person1.firstName}") // working, printing first name
}
class Person(val firstName: String, var age: Int) {
constructor(sectionName: String, id: Int, name: String) : this(sectionName,id) {
println("Age = ${age}") // not working, no output
}
}
Or Am I doing anything wrong?
PS: I know I can write init block and assign the parameters to the class variable and it is working as expected.
You have to call your secondary constructor, which expects a trailing name parameter:
val person1 = Person("Joe", 25, "name") //prints Age = 25
val person2 = Person("Joe", 25) //prints nothing
In your example, the primary constructor gets chosen as your argument list maps its parameters.
in your code val person1 = Person("Joe", 25) your are calling a constructor wich have two parameters and thats the first constructor not the second.
call the second constructor like that val person1 = Person("Joe", 25,"name").
i hope that was clear.
Related
Let's say I have an object
data class Person(
val name: String,
val surname: String,
val street: String,
val postalCode: String,
val telephoneNumber: String,
)
And then I have a list of persons :
val personsList = listOf(
Person(name="John", surname="Hams", street="Gariolg", postalCode="929429", telephoneNumer="+2142422422",),
Person(name="Karl", surname="Hamsteel", street="Gariolg", postalCode="124215", telephoneNumer="+3526522",),
Person(name="Stepf", surname="Hiol", street="Bubmp", postalCode="5342", telephoneNumer="+7574535",),
Person(name="Germa", surname="Foo", street="Hutioa", postalCode="235236", telephoneNumer="+112355",)
)
So now if the user types for instance Hams it should return John and Karl, because both have the word "Hams" inside the object. What I mean is doesn't matter if the user types postalCode, name, or whatever I'd like to loop throughout the object to check if there's any coincidence.
How i would do it, is create a function inside the data class, say, for example, like this. This will check if any field inside your data class matches with the given string.
In my example i check if whole string matches, but you can change this however you want. You probably want it.contains(searchString) inside the any block.
fun checkIfStringMatches(searchString: String) : Boolean =
setOf(this.name, this.surname, this.strees, this.postalCode, this.telephone).any { it == string }
Then, you can use this function on your list of persons to filter if any object matches your string search.
personList.filter{it.checkIfStringMatches(mySearchString)} // this will return a list with all the objects that match your search criteria
The problem is that if you add more fields, you will have to change this function and add it to the listOf() block. But i don't know any way to do this automatically without reflection, which is not really recommended to use. If you still want to use it, here is a question on this topic. Kotlin: Iterate over components of object
Try this, it will work.
personsList.filter { it.surname.startsWith("Hams") }.map {
Log.d("filter_name", it.name)
}
Hey You can apply filter method on list and grab the expected output like below :
val filtered = personsList.filter { it.toString().contains("Hams", true) }
I'm using a simple data class Track, then saving it as an object so that fields and values are automatically saved. This is working as intended. However later when I want to query on 1 of those property/field names, I need to provide the String value.
How do I refer to the name of that property in the data class, so that I maintain the "single source of truth" for that value, without hard coding it a second time in the query? Example uses "spotifyId":
data class Track(
val spotifyId: String,
val name: String,
val artist: List<String>,
val duration: String
)
Save a track:
set(trackDocRef, track)
Query for a track:
db.collection("tracks").whereEqualTo("spotifyId", "sdfgsdfswer4543w5yer345").get()
Thank you!
I figured out one way of doing it, not sure how "correct" it is. I used reflection in the TracksContract object to refer to the Track model:
data class Track(
val spotifyId: String,
val name: String,
val artist: List<String>,
val duration: String
)
Single reference to Track model via TracksContract:
object TracksContract {
internal const val COLLECTION_NAME = "Tracks"
object Fields {
val SPOTIFY_ID = Track::spotifyId.name
val NAME = Track::name.name
val ARTIST = Track::artist.name
val DURATION = Track::duration.name
}
}
now if I need to run the query based on that spotifyId, I refer to through the TracksContract:
db.collection(TracksContract.COLLECTION_NAME)
.whereEqualTo(TracksContract.Fields.SPOTIFY_ID, "ID_VALUE")
.get()
Finally if I decide to change the property names in the Track model then the TracksContract will show a compiler error, and I can change the name and refactor references from there if I want to.
According to the official doc, this is the way to declare a data class
data class User(val name: String, val age: Int)
but most cases i see where data class is declared thus,
data class User(var username: String? = "", var email: String? = "", var age: Int = 0)
explanation from the docs: On the JVM, if the generated class needs to have a parameterless constructor, default values for all properties have to be specified
i don't understand, and what are the implications of the different methods
2ndly, what is the best way of writing a data class containing complex object variables such as, ArrayList, Bitmap, Uri
A parameterless constructor would probably only be necessary if you were using the class with some library that generates instances of your class through reflection, such as a serialization library or dependency injection library.
If you put = and some value after a constructor parameter, it allows you to omit that parameter when calling the constructor. The value you put there will be the default value used when the parameter is omitted. This is usually used as a convenience. But if you are using one of the aforementioned libraries, you would also need an empty constructor. By providing defaults for every parameter and annotating the primary constructor with #JvmOverloads, you can satisfy this requirement. It would look like this:
data class User #JvmOverloads constructor(var username: String? = "", var email: String? = "", var age: Int = 0)
If your data class has a lot of properties, you may not want to use #JvmOverloads because the number of constructors it generates is exponentially proportional to the number of properties with defaults. Instead, you can define a secondary constructor like this:
data class User(var username: String?, var email: String?, var age: Int) {
constructor(): this("", "", 0)
}
Your second question is very open-ended and opinion-based, so near-impossible to answer in a helpful way.
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
}
}
As i have one User class having 2 parameters : first_name, last_name. So my kotlin class with be :
data class User(val first_name:String, val last_name:String)
Now i want a constructor which will accept only first_name, or you can say just one parameter. How can i define it with Kotlin?
I know we can pass default value and in that way we can ignore second parameter, but how can we write multiple constructor?
You can define extra constructors in the class body
data class User(val firstName: String, val lastName: String) {
constructor(firstName: String) : this(firstName, "")
}
These 'secondary constructors' have to call through to the primary constructor or a different secondary constructor. See the Official documentation on constructors.
So, in effect this is the same as just a primary constructor with default argument, which would be the idiomatic way to go.
data class User(val firstName: String, val lastName: String = "")
I hope this will help you
class Person(val name: String, val age: Int = 0) {
override fun toString(): String {
return name + " is " + age + " years Old"
}
}
fun main(args: Array<String>) {
var person = Person(name = "vignesh")
var personNew = Person("vignesh", 23)
println(person.toString())
println(personNew.toString())
}
Output
vignesh is 0 years Old
vignesh is 23 years Old
If you are using data class, then you won't require another constructor. Just pass default value to your last_name parameter.
If you are using a normal class then you can have secondary constructor
Lets say you have class A
class A(val param:String,val param2:String){
constructor(val param:String):this(param,"")
}
If you wish manipulate these values you can use init{} block where you can play around your constructor values.
I hope this will help.
A class in Kotlin can have a primary constructor and one or more secondary constructors. The primary constructor is part of the class header: it goes after the class name (and optional type parameters).
class Person constructor(firstName: String) {
}
If the primary constructor does not have any annotations or visibility modifiers, the constructor keyword can be omitted:
class Person(firstName: String) {
}
Note that parameters of the primary constructor can be used in the initializer blocks. They can also be used in property initializers declared in the class body:
class Customer(name: String) {
val customerKey = name.toUpperCase()
}
You can also follow this link as per your need : Kotlin
This sample of code works fine for me, you can customize them to your need.
data class Booking(
var user: String,
var bike: String
){
constructor(
user: String,
bike: String,
taken_at: String,
returned_at: String
) : this (user, bike)
}