【问题标题】:In which situation val/var is necessary in Kotlin constructor parameter?在 Kotlin 构造函数参数中什么情况下需要 val/var?
【发布时间】:2017-08-22 15:39:11
【问题描述】:

正确的代码:

class MainActHandler(val weakActivity: WeakReference<Activity>): Handler() {
    override fun handleMessage(msg: Message?) {
        val trueAct = weakActivity.get() ?: return
        if (msg?.what == ConversationMgr.MSG_WHAT_NEW_SENTENCE){
            val sentence = msg.obj as String?
            trueAct.conversation.text = sentence
        }
        super.handleMessage(msg)
    }
}

无法解析的代码:

class MainActHandler(weakActivity: WeakReference<Activity>): Handler() {
    override fun handleMessage(msg: Message?) {
        val trueAct = weakActivity.get() ?: return
        if (msg?.what == ConversationMgr.MSG_WHAT_NEW_SENTENCE){
            val sentence = msg.obj as String?
            trueAct.conversation.text = sentence
        }
        super.handleMessage(msg)
    }
}

cannot be resolved code screenshot

唯一的区别是“val”已被删除,无法解析。

重要的是它是一个内部类。

但是

在构造函数参数中没有“val/var”的这个类正在工作:

class BookInfo(convrMgr: ConversationMgr, id: String, queue: RequestQueue, queueTag:String) {

val TAG = "BookInfo"
var title: String? = ""

init {
    val url = "https://api.douban.com/v2/book/$id"
    // Request a string response from the provided URL.
    val stringRequest = StringRequest(Request.Method.GET, url,
            Response.Listener<String> { response ->
                Log.d(TAG + " Response", response.substring(0))
                // Parse JSON from String value
                val parser = Parser()
                val jsonObj: JsonObject =
                        parser.parse(StringBuilder(response.substring(0))) as JsonObject
                // Initial book title of book properties.
                title = jsonObj.string("title")
                Log.d(TAG + " Book title", title)
                convrMgr.addNewMsg(title)
            },
            Response.ErrorListener { error -> Log.e(TAG + " Error", error.toString()) })
    // Set the tag on the request.
    stringRequest.tag = queueTag
    // Add the request to the RequestQueue.
    queue.add(stringRequest)
}

}

如果我在 "queue: RequestQueue" 之前添加 var/val,我会得到建议:

“构造函数参数永远不会用作属性。此检查报告可以删除 'val' 或 'var' 的主要构造函数参数。在主要构造函数中不必要地使用 'val' 和 'var' 会消耗不必要的内存。”

我只是对此感到困惑。

【问题讨论】:

    标签: android kotlin


    【解决方案1】:

    当您在构造函数中编写val/var 时,它会在类中声明一个属性。当你不写它时,它只是传递给主构造函数的一个参数,你可以在其中访问init 块中的参数或使用它来初始化其他属性。例如,

    class User(val id: Long, email: String) {
        val hasEmail = email.isNotBlank()    //email can be accessed here
        init {
            //email can be accessed here
        }
    
        fun getEmail(){
            //email can't be accessed here
        }
    }
    

    构造函数参数从不用作属性

    这个建议是说你不要在初始化之外使用这个属性。因此,它建议您从类中删除此属性。

    【讨论】:

    • 很好的解释。根据documentation,在构造函数的“参数”上指定val 或var 会将参数转换为“属性”。术语"parameter" 是函数签名中变量的名称。构造函数是一种函数。同时,"property" 是类的 getter 和/或 setter,可能还有一个字段来存储数据。
    【解决方案2】:

    构造函数参数在类的其他地方用作属性时必须使用var 或val。如果它们仅用于类初始化,则它们不需要是属性。

    在下面的示例中,参数必须是属性(var 或 val),因为它用于方法中:

    class A(val number: Int) {
        fun foo() = number
    }
    

    在另一个例子中,参数只用于初始化类,所以它不需要是属性:

    class B(number: Int): A(number) {
        init {
            System.out.println("number: $number")
        }
    }
    

    【讨论】:

      【解决方案3】:

      要让@Parcelize 工作,您需要打开超级属性并在子级中覆盖它们:

      abstract class Goal(open var number: Int, open var name: String) : Parcelable
      
      @Parcelize
      class OperationalGoal(override var number: Int, override var name: String, var description: String) : Goal(number, name)```
      

      【讨论】:

        【解决方案4】:

        简单来说,当您想在类的方法中使用该变量时,请在类构造函数参数中使用var 或val。

        class User(var name: String, age: Int) {
            var str = "John"
            var num = 18
        
            //name = str //this will result in a compile error if you uncomment it
        
            fun setName(){
                name = str //due to using var on class constructor parameter, we access constructor variable *name* inside a method
            }
        
            fun setAge(){
                //age = num //this will result in a compile error if you uncomment it, because var wasn't used in the *age* parameter within the class constructor, which means we can't access *age*
            }
            
        }
        

        Run this Kotlin Playground code to get a clearer idea of what's going on.

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-07-06
          • 2020-03-10
          • 2011-02-25
          • 1970-01-01
          • 2012-09-15
          • 2018-06-02
          相关资源
          最近更新 更多