I want to define my own accessor for a field, like this:
var item: Item
get() {...}
set(value) {...}
I get an error because item is not initialized. I cant add lateinit because I define the get and set methods.
What I can choose is to declare another nullable field, and use that field to implement the item accessors, which is too stupid and redundant.
So I guess there must other ways to implement this requirement...
update:
Thanks for you reply.
I think I didnt express it clearly. And After I read the doc multiple times, I think the answer is NO.
My requirement is: Is there an easier alternative way to declare this?
private var _table: Map<String, Int>? = null
public val table: Map<String, Int>
get() {
if (_table == null)
_table = HashMap() // Type parameters are inferred
return _table ?: throw AssertionError("Set to null by another thread")
}
We have to declare a nullabe backing property so we can customize accessors and also leave the field uninitialized.
If you declare a property with a backing field, you need to initialize it. If you don't want do initialize it, you can declare custom getters and setters.
var item: String
get() = "my String"
set(value) {
log(value)
//do something with value
}
If you don't have a value to initialize the property with, declare it nullable and initialize it with null
var item: String? = null
get() = field
set(value) {
field = value
//do something with value
}
If this doesn't match your requirements, please update the question to clarify.
Related
I have a homework question "Implement a val property that returns a different value on each access"
I can imagine how I can return different values with function, but not with variable. Is there some "linux-like" link to this function in Kotlin I should make?
This is a simple example. I recommend reading Kotlin's documentation on getters and setters.
class CustomGetter {
private var underlyingField: Int = 0
private var alwaysHigher: Int = this.underlyingField
get() {
this.underlyingField++
field = underlyingField
return field
}
}
Given a Kotlin data class, how do you initialize a non-nullable property as a pointer to self? I.e something like the following pseudocode.
data class Node(var other: Node = this)
Currently I have a solution that introduces temporary properties
data class Node(val _other: Node? = null) {
var other: Node = _other ?: this
}
This is not possible. You cannot access this before it is constructed. But that's just how the default constructor parameter would work.
Cannot access '<this>' before superclass constructor has been called
Thank you for your feedback, however, for my purposes I need the functionality of a data class like equals and copy and I would prefer not to have make the property nullable and/or implementing the functionality manually.
You'd still have to: equals and copy will care only about _other and ignore other (just as they would ignore all other properties defined in the body of the class). That other is a var just makes it worse: reassigning it will have no effect on data class functionality.
But you can come closer:
data class Node(private var _other: Node? = null) {
var other: Node
get() = _other ?: this
set(value) {
_other = if (value != this) value else null
}
}
The only problem remaining is that component1() will return _other. In this case you have a single property so it shouldn't matter.
EDIT: after thinking a bit more,
data class Node(private var _other: Node? = null) {
init {
this._other = _other ?: this
}
var other: Node
get() = _other!! // safe
set(value) {
_other = value
}
}
seems to effectively be what you want. You can see difference here:
val node1 = Node()
val node2 = node1.copy(node1)
println(node1 == node2)
prints false with the first solution, true with the second one (as it should if this was the default parameter).
Currently I'm starting to learn Kotlin. I have a property like this:
var startTime: Int
get() = {
// read value from database
}
set(value) {
// save value to database
}
Here I always read and write the value every time I use the getter and setter.
Can this property be evaluated lazy? I want to read the value once the first time I use the getter and cache it for following calls. I know that values can be lazy but I found nothing about variables. What is the correct way in Kotlin to cache this property?
Kotlin offers lazy properties (https://kotlinlang.org/docs/reference/delegated-properties.html#lazy) that are computed on first access and cached.
val lazyValue: String by lazy {
println("computed!")
"Hello"
}
fun main(args: Array<String>) {
println(lazyValue)
println(lazyValue)
}
Will produce
computed!
Hello
Hello
What you need is not lazy evaluation, but a backing field:
private var _startTime: Int? = null
var startTime: Int
get() = {
if (_startTime != null) {
return _startTime!!
} else {
// read value from database and assign it to _startTime
}
}
set(value) {
_startTime = value
// save value to database
}
Alternatively you could declare _startTime as non-nullable and have an additional flag private var isStartTimeSet: Boolean = false used for checking if it has been fetched from database already.
I find it can only access backing field in the set or get.Is there any way can access backing field in other place at class?
for example.
var width:Int=0
get() {
return field*10;
}
set(value) {
field=value/10;
}
I want to access the real value but not it multiple 10
when i using c#,there are no field keyword so always need to declare a new variable to store the real data.In the previous example it's will be something look like
private var _width=0;
var width:Int
get() {
return _width*10;
}
set(value) {
_width=value/10;
}
so if i want to access real value in the class,i can just access _value.
But in kotlin,is there have someway can just access backing field without these verbose declaration?
No. Your C# example works fine in Kotlin, it's called a backing property.
Kotlin, You can use backing properties
Backing Properties
If you want to do something that does not fit into this "implicit backing field" scheme, you can always fall back to having a backing property:
private var _table: Map<String, Int>? = null
public val table: Map<String, Int>
get() {
if (_table == null) {
_table = HashMap() // Type parameters are inferred
}
return _table ?: throw AssertionError("Set to null by another thread")
}
In all respects, this is just the same as in Java since access to private properties with default getters and setters is optimized so that no function call overhead is introduced.
I have a data class
data class MyModel(private val _data: MyData? = null)
And I want to ensure my data is only accessible when it is not null, else throw.
I use the below which is good.
fun getData(): MyData {
return checkNotNull(_data) { "data shouldn't be null" }
}
However, if I follow the guide as per Override getter for Kotlin data class, the below complaints I need to return MyData? instead of MyData
val data = _data
get(): MyData {
return checkNotNull(field) { "data shouldn't be null" }
}
Is it true that field can't be cast to the Non-null version of it when return?
If your goal is to declare a getter for a Any? property that returns a Any, it's not possible. You'll get the following error:
Getter return type must be equal to the type of the property
So attempting to do something like
val test : String?
get() : String = "hi"
Wouldn't work.
However, you could hide the nullable property and expose a non-nullable property which references the nullable value via casting:
private val test : String? = "hi"
val testNotNull : String = test as String
If test referenced null, an exception will be thrown.
For example:
fun main(args: Array<String>) = print(Demo().testNotNull)
class Demo(private var test: String? = "hi") {
val testNotNull : String
. get() = test as String
}
You can test this snippit out at try.kotlin.org
Although this is not safe. You should rethink your design. If you're not interoping with Java, you shouldn't punish yourself with nullable types.
I don’t think you can. What you did with the fun getData() is a valid approach IMO. Or you could just not use a data class and create a normal class, obviously.
What I think it may work is with something like this:
typealias notNullType = MyData
data class Test(private val _value: MyData? = null) {
val v: notNullType = _value as notNullType
get() { return field }
}
This would totally allow you to do:
fun play() {
val t = Test(null)
print(t.v) //see what I did? :-)
}
THAT BEING SAID… I don’t think “hiding” the ? optional is necessarily a good idea.
It doesn't necessarily mean that the MyData class is null if you cast it like MyData?
The '?' Just allows the object to be null in the instance that it actually becomes null to avoid an exception at runtime.
You can make your class nullable and it can still contain your data.