Getters and Setters ใน Kotlin


89

ตัวอย่างเช่นใน Java ฉันสามารถเขียน getters ด้วยตัวเอง (สร้างโดย IDE) หรือใช้คำอธิบายประกอบเช่น @Getter ในลอมบอกซึ่งค่อนข้างง่าย

Kotlin แต่มีgetters และ setters โดยค่าเริ่มต้น แต่ฉันไม่เข้าใจวิธีใช้

ฉันต้องการทำเช่นนั้น - คล้ายกับ Java:

private val isEmpty: String
        get() = this.toString() //making this thing public rises an error: Getter visibility must be the same as property visibility.

แล้ว getters ทำงานอย่างไร?

คำตอบ:


148

Getters และ setters ถูกสร้างขึ้นโดยอัตโนมัติใน Kotlin ถ้าคุณเขียน:

val isEmpty: Boolean

เท่ากับรหัส Java ต่อไปนี้:

private final Boolean isEmpty;

public Boolean isEmpty() {
    return isEmpty;
}

ในกรณีของคุณตัวแก้ไขการเข้าถึงส่วนตัวซ้ำซ้อน - isEmpty เป็นส่วนตัวโดยค่าเริ่มต้นและสามารถเข้าถึงได้โดย getter เท่านั้น เมื่อคุณพยายามรับคุณสมบัติ isEmpty ของอ็อบเจ็กต์คุณจะเรียกเมธอด get ตามความเป็นจริง เพื่อความเข้าใจมากขึ้นเกี่ยวกับ getters / setters ใน Kotlin: ตัวอย่างโค้ดทั้งสองด้านล่างมีค่าเท่ากัน:

var someProperty: String = "defaultValue"

และ

var someProperty: String = "defaultValue"
    get() = field
    set(value) { field = value }

นอกจากนี้ฉันต้องการชี้ให้เห็นว่าthisใน getter ไม่ใช่ทรัพย์สินของคุณ - เป็นตัวอย่างของคลาส หากคุณต้องการเข้าถึงค่าของฟิลด์ใน getter หรือ setter คุณสามารถใช้คำสงวนfieldสำหรับมัน:

val isEmpty: Boolean
  get() = field

หากคุณต้องการเพียงแค่มีเมธอด get ในการเข้าถึงสาธารณะ - คุณสามารถเขียนโค้ดนี้:

var isEmpty: Boolean
    private set 

เนื่องจากตัวปรับแต่งส่วนตัวใกล้กับ set accessor คุณสามารถตั้งค่านี้ได้เฉพาะในวิธีการภายในวัตถุของคุณ


17
In your case the private access modifier is redundantอย่างไร? Kotlin doc พูดว่าตัวปรับแต่งเริ่มต้นเป็นสาธารณะ kotlinlang.org/docs/reference/visibility-modifiers.html

@ ไม่มีอะไรที่ดูเหมือนว่าสนามสาธารณะ แต่ภายใต้ประทุนคุณเรียกวิธี getter
Cortwave

val isEmpty: Booleanจะไม่รวบรวมเป็น isEmpty ยังไม่ได้เริ่มต้นใช่มั้ย? เพิ่งเริ่มเรียน Kotlin นอกจากนี้เกิดอะไรขึ้นกับget() = field?
Shubham

1
@Chiara valไม่มี setter
chroder

@chroder ใช่คุณพูดถูกฉันต้องอ่านผิด ... ความคิดเห็นถูกลบ ขอบคุณที่ชี้ให้ดู
Chiara

30

กฎเกี่ยวกับตัวปรับเปลี่ยนการมองเห็นคุณสมบัติ accessors มีดังต่อไปนี้:

  • การมองเห็นของ Getter varและvalคุณสมบัติควรจะเหมือนกันทุกประการกับการมองเห็นของคุณสมบัติดังนั้นคุณสามารถทำซ้ำตัวปรับแต่งคุณสมบัติอย่างชัดเจนเท่านั้น แต่มันซ้ำซ้อน:

    protected val x: Int
        protected get() = 0 // No need in `protected` here.
    
  • การเปิดเผยvarทรัพย์สินของ Setter ควร เหมือนหรือได้รับอนุญาตน้อยกว่าการเปิดเผยคุณสมบัติ:

    protected var x: Int
        get() = 0
        private set(x: Int) { } // Only `private` and `protected` are allowed.
    

ใน Kotlin คุณสมบัติจะถูกเข้าถึงผ่าน getter และ setter เสมอดังนั้นจึงไม่จำเป็นต้องสร้างคุณสมบัติprivateด้วยpublicaccessors เช่นใน Java - ฟิลด์แบ็คกิ้ง (ถ้ามี)เป็นแบบส่วนตัวอยู่แล้ว ดังนั้นตัวปรับการมองเห็นบนตัวเข้าถึงคุณสมบัติจึงใช้เพื่อทำให้การมองเห็นของ setter ได้รับอนุญาตน้อยลงเท่านั้น:

  • สำหรับคุณสมบัติที่มีฟิลด์สำรองและตัวเข้าถึงเริ่มต้น:

    var x = 0 // `public` by default
        private set
    
  • สำหรับคุณสมบัติที่ไม่มีฟิลด์สำรอง:

    var x: Int // `public` by default
        get() = 0
        protected set(value: Int) { }
    

หนึ่งชุดและรับประเภทต่างๆได้หรือไม่? การตั้งค่าx เท่ากับบางส่วน"Some String"และส่งกลับบอกความยาว11ของสตริง?
Carel

@Carel ไม่ ณ ตอนนี้ไม่รองรับกรณีการใช้งานนี้: ตัวเข้าถึงของคุณสมบัติควรทำงานกับประเภทของคุณสมบัติ การใช้ประเภทอื่นจะครอบคลุมโดยใช้คุณสมบัติสำรองแยกต่างหาก
ฮ็อตคีย์

ยี้ Kotlin อยู่ใกล้กับ Python มากจนคุณคิดว่ามันจะใช้งานได้ก็ต่อเมื่อคุณได้รับการเตือนว่ามันพิมพ์ ... และเชือดคอของคุณเอง
Carel

ขอบคุณสำหรับการปรับเปลี่ยนการเข้าถึง ฉันลบออกprivateจากตัวแปรและสามารถเข้าถึงได้จากคลาสอื่นด้วย getter
CoolMind

ฉันได้รับ "Private setters ไม่ได้รับอนุญาตสำหรับคุณสมบัติแบบเปิด" เมื่อใช้ชุดค่าผสม "var x // private set" แก้ไขได้โดยประกาศเป็น "final var x"
ทอม

15

1) ตัวอย่างค่าเริ่มต้นsetterและgetterสำหรับคุณสมบัติ firstNameใน Kotlin

class Person {
    var firstName: String = ""
            get() = field       // field here ~ `this.firstName` in Java or normally `_firstName` is C#
            set(value) {
                field = value
            }

}

การใช้

val p = Person()
p.firstName = "A"  // access setter
println(p.firstName) // access getter (output:A)

หากคุณsetterหรือgetterเป็นเดียวกันว่าข้างต้นคุณสามารถลบมันเพราะมันเป็นที่ไม่จำเป็น

2) ตัวอย่าง setter และ getter ที่กำหนดเอง

const val PREFIX = "[ABC]"

class Person {

    // set: if value set to first name have length < 1 => throw error else add prefix "ABC" to the name
    // get: if name is not empty -> trim for remove whitespace and add '.' else return default name
    var lastName: String = ""
        get() {
            if (!field.isEmpty()) {
                return field.trim() + "."
            }
            return field
        }
        set(value) {
            if (value.length > 1) {
                field = PREFIX + value
            } else {
                throw IllegalArgumentException("Last name too short")
            }
        }
}

การใช้

val p = Person()
p.lastName = "DE         " // input with many white space
println(p.lastName)  // output:[ABC]DE.
p.lastName = "D" // IllegalArgumentException since name length < 1

เพิ่มเติม
ฉันจะเริ่มต้นเรียนรู้ Kotlin จาก Java ดังนั้นฉันสับสนเกี่ยวกับfieldและpropertyเพราะใน Java propertyไม่มี
หลังจากการค้นหาฉันเห็นfieldและpropertyใน Kotlin ดูเหมือน C # ( ความแตกต่างระหว่างฟิลด์และคุณสมบัติคืออะไร? )

นี่คือโพสต์ที่เกี่ยวข้องซึ่งพูดถึงfieldและpropertyใน Java และ Kotlin
java มีคุณสมบัติคล้ายกับ C # หรือไม่
https://blog.kotlin-academy.com/kotlin-programmer-dictionary-field-vs-property-30ab7ef70531

แก้ไขฉันถ้าฉันผิด หวังว่าจะช่วยได้


ขอบคุณมันช่วยฉันได้จริงๆ!
marcode_ely

8

Getter ใน kotlin เป็นค่าเริ่มต้นสาธารณะ แต่คุณสามารถตั้งค่าตัวตั้งค่าเป็นส่วนตัวและตั้งค่าโดยใช้วิธีการเดียวในคลาส แบบนี้.

/**
* Created by leo on 17/06/17.*/

package foo
class Person() {
var name: String = "defaultValue"
               private set

fun foo(bar: String) {
    name = bar // name can be set here
       }
}

fun main(args: Array<String>) {
  var p = Person()
  println("Name of the person is ${p.name}")
  p.foo("Jhon Doe")
  println("Name of the person is ${p.name}")
}

5

คุณสามารถดูบทช่วยสอนนี้สำหรับข้อมูลเพิ่มเติม:

อีกหนึ่งบทช่วยสอน Kotlin สำหรับนักพัฒนา Android

คุณสมบัติ

ในโลก Kotlin คลาสไม่สามารถมีฟิลด์ได้มีเพียงคุณสมบัติ var คำหลักบอกเราว่าคุณสมบัติไม่แน่นอนตรงกันข้ามกับ val ลองดูตัวอย่าง:

class Contact(var number: String) {

   var firstName: String? = null
   var lastName: String? = null
   private val hasPrefix : Boolean
       get() = number.startsWith("+")

}

ไม่มีรหัสมากนัก แต่มีหลายสิ่งเกิดขึ้นเบื้องหลัง เราจะผ่านมันไปทีละขั้นตอน ก่อนอื่นเราได้สร้างที่ติดต่อสาธารณะขั้นสุดท้าย

นี่คือกฎหลักที่เราต้องเผชิญ: หากไม่ได้ระบุไว้เป็นอย่างอื่นคลาสจะเป็นแบบสาธารณะและเป็นขั้นสุดท้ายโดยค่าเริ่มต้น (โดยวิธีเดียวกันนี้ใช้สำหรับเมธอดคลาส) หากคุณต้องการสืบทอดจากคลาสให้ทำเครื่องหมายด้วยคีย์เวิร์ดเปิด


0

นี่คือตัวอย่างที่ใช้งานได้จริงของ Kotlin getter and setter (ดูรายละเอียดเพิ่มเติมที่นี่ ):

// Custom Getter
val friendlyDescription get(): String {
    val isNeighborhood = district != null
    var description = if (isNeighborhood) "Neighborhood" else "City"
    description += " in"
    if (isNeighborhood) {
        description += " $city,"
    }
    province?.let {
        if (it.isNotEmpty()) {
            description += " $it,"
        }
    }
    description += " $country"
    return description
}

print(myLocation.friendlyDescription) // "Neighborhood in Denver, Colorado, United States"


// Custom Setter
enum class SearchResultType {
    HISTORY, SAVED, BASIC
}

private lateinit var resultTypeString: String

var resultType: SearchResultType
    get() {
        return enumValueOf(resultTypeString)
    }
    set(value) {
        resultTypeString = value.toString()
    }

result.resultType = SearchResultType.HISTORY
print(result.resultTypeString) // "HISTORY"

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.