Groovy类使用另一个实例字段

huangapple go评论74阅读模式
英文:

Groovy class use another instance field

问题

我正试图构建一个具有属性的Groovy类,并且有一个属性依赖于另一个属性。但我似乎总是得到一个空值或默认值。我尝试使用'this'关键字,但我漏掉了某些基本内容。我知道这可能与实例变量有关。

假设我有以下内容:

class BaseClass {
    String jobName
    String jobDescription = jobName + '-description'
}

如果我实例化该类并声明两个属性,一切正常:

new BaseClass().with {
    jobName = 'test-job'
    jobDescription = 'Sample description'
}

但如果我只实例化jobName属性,描述将使用null。因此它将是'null-description'。

有没有办法我可以实例化一个对象并使用jobName属性,这样我就不必为我创建的每个对象重复自己?

英文:

I am trying to build a Groovy class with properties and have one property depend on one another. But I always seem to get a null or default value. I tried using the 'this' keyword but I am missing something fundamental. I know it probably has something to do with instance variables.

Say I have the following:

class BaseClass {
    String jobName
    String jobDescription = jobName + '-description'
}

If I instantiate the class and declare both attributes, everything works:

new BaseClass().with {
        jobName = 'test-job'
        jobDescription = 'Sample description'
    }

But if I only instantiate the jobName property, the description uses null. So it will be 'null-description'.

Is there any way I can instantiate an object and use the jobName property so I don' have to repeat myself for every object I create?

答案1

得分: 3

我认为最好的方法是覆盖jobName的setter,然后进行防御性设置描述。例如:

class BaseClass {

    String jobName

    String jobDescription

    void setJobName(String jobName) {
        this.jobName = jobName
        if (!jobDescription) {
            jobDescription = "${jobName}-description"
        }
    }
}

assert new BaseClass().tap{ jobName = 'test-job' }.jobDescription == 'test-job-description';

你尝试的方法之所以没有按预期工作,是因为事情发生的流程 - 属性的默认值是在对象构造时完成的。因此,在with中稍后设置作业没有效果(它不会从新输入重新计算)。

另一个选择是基于构造函数的方法(例如,使用final并在构造函数中处理此问题以创建默认描述)。

英文:

I think you are best off with overriding the setter for jobName and then defensively set the description. E.g.

class BaseClass {

	String jobName

	String jobDescription

	void setJobName(String jobName) {
		this.jobName = jobName
		if (!jobDescription) {
			jobDescription = "${jobName}-description"
		}
	}
}

assert new BaseClass().tap{ jobName = 'test-job' }.jobDescription == 'test-job-description'

The reason your attempt does not work as expected is due to the flow of things happening - the attribute default is done at construction time of the object. So setting the job later (inside the with) has no effect (it will not be calculated again from the new input).

Another option would be an constructor based approach (e.g. use final and deal with this problem in the c'tor to create a default description)

答案2

得分: 1

为了我理解,初始化将在 'with' 之前执行(我知道这实际上不是一个函数...),所以 jobDescription 已经被设置为 'null-description',并且它不会在 'with' 中被更改。

我对 Groovy 不是很熟悉(我仍然拼写成 'Gruwi'),但我认为它也会有定义带有代码的构造函数的功能,我会假设这会在 'with' 之后执行。因此,当您将初始化放在那里,并检查属性是否仍为 null 时,它应该能够正常工作。

希望这不是完全无意义的…

英文:

For my understanding, the initialisation will be executed before the 'with' (I know this is not really a function …), so jobDescription is set to 'null-description' already, and it will not be changed in the 'with'.

I am not very familiar with Groovy (I still spell it 'Gruwi'), but I think it will have also the feature to define a constructor with code, and I would assume that this is executed after 'with'. So when you place the initialisation there, with a check if the attribute is still null, it should work.

Hope this is not complete nonsense …

huangapple
  • 本文由 发表于 2020年3月16日 19:35:26
  • 转载请务必保留本文链接:https://go.coder-hub.com/60705247.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定