Private getter and public setter for a Kotlin property

后端 未结 3 1343
梦谈多话
梦谈多话 2020-12-05 09:17

How to make a property in Kotlin that has a private getter (or just do not have it) but has a public setter?

var status
private get

doesn\'

相关标签:
3条回答
  • 2020-12-05 09:36

    Write-only properties with compile-time errors can be achieved since Kotlin 1.0, using a workaround based on @Deprecated.

    Implementation

    Kotlin allows to mark functions deprecated with level ERROR, which leads to a compile-time error when called. Annotating the get accessor of a property as error-deprecated, combined with a backing field (so that private reads are still possible), achieves the desired behavior:

    class WriteOnly {
        private var backing: Int = 0
    
        var property: Int
            @Deprecated("Property can only be written.", level = DeprecationLevel.ERROR)
            get() = throw NotImplementedError()
            set(value) { backing = value }
    
        val exposed get() = backing // public API
    }
    

    Usage:

    val wo = WriteOnly()
    wo.property = 20         // write: OK
    
    val i: Int = wo.property // read: compile error
    val j: Int = wo.exposed  // read value through other property
    

    The compile error is quite helpful, too:

    Using 'getter for property: Int' is an error. Property can only be written.


    Use cases

    1. The main use case are obviously APIs that allow properties to be written, but not read:

      user.password = "secret"
      val pw = user.password // forbidden
      
    2. Another scenario is a property which modifies the internal state, but is not stored itself as a field. (Could be done more elegantly using different design).

      body.thrust_force = velocity
      body.gravity_force = Vector(0, 0, 9.8)
      // only total force accessible, component vectors are lost
      val f = body.forces
      
    3. This pattern is also useful for DSLs of the following kind:

      server {
          port = 80
          host = "www.example.com"
      }
      

      In such cases, values are simply used as one-time settings, and the write-only mechanism described here can prevent accidentally reading a property (which might not be initialized yet).


    Limitations

    Since this feature was not designed for this use case, it comes with certain limitations:

    • If accessed using a property reference, the compile-time error turns into a runtime error:

      val ref = wo::property
      val x = ref.get() // throws NotImplementedError
      
    • The same is true for reflection.

    • This functionality cannot be outsourced into a delegate, because an error-deprecated getValue() method cannot be used with by.

    0 讨论(0)
  • 2020-12-05 09:39

    In current Kotlin version (1.0.3) the only option is to have separate setter method like so:

    class Test {
        private var name: String = "name"
    
        fun setName(name: String) {
            this.name = name
        }
    }
    

    If you wish to restrict external libraries from accessing the getter you can use internal visibility modifier allowing you to still use property syntax within the library:

    class Test {
        internal var name: String = "name"
        fun setName(name: String) { this.name = name }
    }
    
    fun usage(){
        val t = Test()
        t.name = "New"
    }
    
    0 讨论(0)
  • 2020-12-05 09:54

    It's impossible at the moment in Kotlin to have a property with a setter that is more visible than the property. There's a language design issue in the issue tracker on this, feel free to watch/vote for it or share your use cases: https://youtrack.jetbrains.com/issue/KT-3110

    0 讨论(0)
提交回复
热议问题