覆盖getValue和setValue以大写一对

时间:2018-08-14 14:57:08

标签: kotlin

假设我有以下课程:

class Person() {
    var age: Pair<String, Int> = Pair("person_age", 23)
    // override getValue and setValue here
}

现在,我想封装实际的Pair,只希望用户读取/写入该对的第二个值。是否可以覆盖getValuesetValue方法,以便我可以执行以下操作:

val p = Person()
p.age = 25

if(p.age <= 30)

当然,我可以为每个属性编写自己的gettersetter方法,但是Kotlin的一件好事是,您必须编写更少的样板代码,然后这些代码会丢失。

4 个答案:

答案 0 :(得分:1)

以下内容可能已经足够:

class Person() {
  var age : Int = 23 // public by default
  private /* or internal */ fun toAgePair() = "person_age" to age // narrow visibility
}

因此,您所有的代码都可以访问显示的年龄:

val p = Person()
p.age = 25
if (p.age <= 30) ...

但是,如果您需要Pair,请执行以下操作:

p.toAgePair() // or skip that method and use: '"person_age" to p.age' instead

访问Pair内容的替代方法是:Pair.firstPair.seconddestructured,例如:

val myPair = Pair("person_age", 23)
// myPair.second = 25 // setting will not work however
myPair.let { (name, age) -> /* do something with it */ }

或者:

val p = Person()
val (name, age) = p.toAgePair()
// age = 25 // setting will not work however (and it wouldn't set the actual value inside the Pair if it would contain vars)
if (age < 30) // accessing is OK

但是,如果我正确地理解了您的信息,那么您就可以同时访问您可能不想使用的两个值。 您可以使用自己的data classvar来克服设置部分,但是再次,您并不能从中真正受益。

答案 1 :(得分:1)

  

现在,我想对实际的货币对大写,只希望用户读取/写入货币对的第二个值。

假设这意味着您希望第一个值是最终值,而不是第二个,那么有一些选择。

如果只希望其中一个值可写和可读,请不要使用一对。它并非旨在那样使用。一对中的所有项目均为val

如果您希望以任何一种方式配对,可以执行以下操作:

class Person(var age: Int = 23){
    val pair: Pair<String, Int>
        get() = Pair("person_age", age)
    //Alternatively, if you don't want to use a property:
    //fun getPair() = "person_age" to age
}

这是创建一个最终对,其中第一个值不能修改,而第二个可以修改。

所以现在:

fun example(){
    val person = Person()
    person.age = 25;//Fine: Age is an int, and a var
    //person.pair = Pair("something", 45)//fails: "Val cannot be reassigned
    val pair = person.pair // Allowed. Accessing the pair still works
    assert(pair.second == person.age) // This is true
}

但是,如果您对非配对解决方案感到满意,那么它也可以工作:

data class Person (var age: Int, val string: String = "person_age")

fun example(){
    val person = Person(23)
    val (name, string) = person// Allowed! Just like with Pairs
    person.age = 25; // Also allowed
    //person.string = "something"//Not allowed
}

数据类支持n折叠。如果没有数据类,则需要为要解压缩的每个组件声明一个operator fun。示例:

class Person (val string: String = "person_age", var age: Int){
    operator fun component1() = string
    operator fun component2() = age
}

但是,听起来,data class解决方案是您正在寻找的解决方案。它将把String锁定为其初始化的对象,并且由于默认值及其位置,您可以使用单个定位参数进行初始化*

如果要将同一类用于多种类型,则也可以使用泛型。

*假定代码在Kotlin中。定位参数和默认参数不适用于Java代码。

答案 2 :(得分:1)

我完全不建议您使用Pair。也许您可以修改它(继承自它,使用扩展功能)以满足您的需要,但是为什么要尝试更改诸如Pair这样简单的东西呢?只需创建自己的类来满足您的需求就容易得多,在这种情况下也更干净:

data class MyPair<out A, B>(
    val first: A, 
    var second: B
)

val pair = MyPair("age", 1)
pair.second = 2
pair.first = 1 // error

此类具有Pair具有的所有重要功能:firstsecond的通用类型,您可以使用解构声明。

答案 3 :(得分:1)

这是在Kotlin中覆盖getter方法的方法

class Person {
    var age: Int = 0
       get() = if (field < 0) 0 else field 

}

可以直接访问属性

fun main(args: Array<String>) {

    val p = Person()
    p.age = -28
    println(p.age) //0
}