字段可以转换为非null版本吗?

时间:2017-07-11 01:18:06

标签: kotlin kotlin-null-safety

我有一个数据类

data class MyModel(private val _data: MyData? = null)

我想确保我的数据只有在非空时才可访问,否则抛出。 我用下面这个很好。

    fun getData(): MyData {
        return checkNotNull(_data) { "data shouldn't be null" }
    }

但是,如果我按照Override getter for Kotlin data class按照指南操作,则需要返回以下投诉MyData?而不是MyData

val data = _data
    get(): MyData {
        return checkNotNull(field) { "data shouldn't be null" }
    }

返回时,field是否无法转换为非null版本?

3 个答案:

答案 0 :(得分:2)

如果您的目标是为Any?属性声明一个返回Any的getter,那么这是不可能的。您将收到以下错误:

  

Getter返回类型必须等于属性的类型

因此尝试做类似

的事情
val test : String?
    get() : String = "hi"

不行。

但是,您可以隐藏可空属性并公开一个不可为空的属性,该属性通过强制转换引用可为空的值:

private val test : String? = "hi"
val testNotNull : String = test as String

如果test引用null,则会引发异常。

例如:

fun main(args: Array<String>) = print(Demo().testNotNull)

class Demo(private var test: String? = "hi") {
    val testNotNull : String
.       get() = test as String
}

您可以在try.kotlin.org

处测试此snippit

虽然这不安全。你应该重新考虑你的设计。如果你没有使用Java,你不应该用可空类型惩罚自己。

答案 1 :(得分:1)

我认为你不能。您对public enum TimeType { emptyLoop = 1, loopEmptyFunction = 2, loopNullCheck = 3, loopNullCheckShort = 4, loopNullCheckInstanceNotNull = 5, loopNullCheckInstanceNotNullShort = 6, loopEmptyStaticFunction = 7 } class myTime { public double miliseconds { get; set; } public long ticks { get; set; } public TimeType type { get; set; } public myTime() { } public myTime(Stopwatch stopwatch, TimeType type) { miliseconds = stopwatch.Elapsed.TotalMilliseconds; ticks = stopwatch.ElapsedTicks; this.type = type; } } class myClass { public static void staticEmptyFunction() { } public void emptyFunction() { } } class Program { static List<myTime> timesList = new List<myTime>(); static int testTimesCount = 10000; static int oneTestDuration = 100000; static void RunTest() { Stopwatch stopwatch = new Stopwatch(); Console.Write("TEST "); for (int j = 0; j < testTimesCount; j++) { Console.Write("{0}, ", j + 1); myClass myInstance = null; // 1. EMPTY LOOP stopwatch.Start(); for (int i = 0; i < oneTestDuration; i++) { } stopwatch.Stop(); timesList.Add(new myTime(stopwatch, (TimeType)1)); stopwatch.Reset(); // 3. LOOP WITH NULL CHECKING (INSTANCE IS NULL) stopwatch.Start(); for (int i = 0; i < oneTestDuration; i++) { if (myInstance != null) myInstance.emptyFunction(); } stopwatch.Stop(); timesList.Add(new myTime(stopwatch, (TimeType)3)); stopwatch.Reset(); // 4. LOOP WITH SHORT NULL CHECKING (INSTANCE IS NULL) stopwatch.Start(); for (int i = 0; i < oneTestDuration; i++) { myInstance?.emptyFunction(); } stopwatch.Stop(); timesList.Add(new myTime(stopwatch, (TimeType)4)); stopwatch.Reset(); myInstance = new myClass(); // 2. LOOP WITH EMPTY FUNCTION stopwatch.Start(); for (int i = 0; i < oneTestDuration; i++) { myInstance.emptyFunction(); } stopwatch.Stop(); timesList.Add(new myTime(stopwatch, (TimeType)2)); stopwatch.Reset(); // 5. LOOP WITH NULL CHECKING (INSTANCE IS NOT NULL) stopwatch.Start(); for (int i = 0; i < oneTestDuration; i++) { if (myInstance != null) myInstance.emptyFunction(); } stopwatch.Stop(); timesList.Add(new myTime(stopwatch, (TimeType)5)); stopwatch.Reset(); // 6. LOOP WITH SHORT NULL CHECKING (INSTANCE IS NOT NULL) stopwatch.Start(); for (int i = 0; i < oneTestDuration; i++) { myInstance?.emptyFunction(); } stopwatch.Stop(); timesList.Add(new myTime(stopwatch, (TimeType)6)); stopwatch.Reset(); // 7. LOOP WITH STATIC FUNCTION stopwatch.Start(); for (int i = 0; i < oneTestDuration; i++) { myClass.staticEmptyFunction(); } stopwatch.Stop(); timesList.Add(new myTime(stopwatch, (TimeType)7)); stopwatch.Reset(); } Console.WriteLine("\nDONE TESTING"); } static void GetResults() { // SUMS double sum1t, sum2t, sum3t, sum4t, sum5t, sum6t, sum7t, sum1m, sum2m, sum3m, sum4m, sum5m, sum6m, sum7m; sum1t = sum2t = sum3t = sum4t = sum5t = sum6t = sum7t = sum1m = sum2m = sum3m = sum4m = sum5m = sum6m = sum7m = 0; foreach (myTime time in timesList) { switch (time.type) { case (TimeType)1: sum1t += time.ticks; sum1m += time.miliseconds; break; case (TimeType)2: sum2t += time.ticks; sum2m += time.miliseconds; break; case (TimeType)3: sum3t += time.ticks; sum3m += time.miliseconds; break; case (TimeType)4: sum4t += time.ticks; sum4m += time.miliseconds; break; case (TimeType)5: sum5t += time.ticks; sum5m += time.miliseconds; break; case (TimeType)6: sum6t += time.ticks; sum6m += time.miliseconds; break; case (TimeType)7: sum7t += time.ticks; sum7m += time.miliseconds; break; } } // AVERAGES double avg1t, avg2t, avg3t, avg4t, avg5t, avg6t, avg7t, avg1m, avg2m, avg3m, avg4m, avg5m, avg6m, avg7m; avg1t = sum1t / (double)testTimesCount; avg2t = sum2t / (double)testTimesCount; avg3t = sum3t / (double)testTimesCount; avg4t = sum4t / (double)testTimesCount; avg5t = sum5t / (double)testTimesCount; avg6t = sum6t / (double)testTimesCount; avg7t = sum7t / (double)testTimesCount; avg1m = sum1m / (double)testTimesCount; avg2m = sum2m / (double)testTimesCount; avg3m = sum3m / (double)testTimesCount; avg4m = sum4m / (double)testTimesCount; avg5m = sum5m / (double)testTimesCount; avg6m = sum6m / (double)testTimesCount; avg7m = sum7m / (double)testTimesCount; string fileName = "/result.txt"; using (StreamWriter tr = new StreamWriter(AppDomain.CurrentDomain.BaseDirectory + fileName)) { tr.WriteLine(((TimeType)1).ToString() + "\t" + avg1t + "\t" + avg1m); tr.WriteLine(((TimeType)2).ToString() + "\t" + avg2t + "\t" + avg2m); tr.WriteLine(((TimeType)3).ToString() + "\t" + avg3t + "\t" + avg3m); tr.WriteLine(((TimeType)4).ToString() + "\t" + avg4t + "\t" + avg4m); tr.WriteLine(((TimeType)5).ToString() + "\t" + avg5t + "\t" + avg5m); tr.WriteLine(((TimeType)6).ToString() + "\t" + avg6t + "\t" + avg6m); tr.WriteLine(((TimeType)7).ToString() + "\t" + avg7t + "\t" + avg7m); } } static void Main(string[] args) { RunTest(); GetResults(); Console.ReadLine(); } } 所做的是IMO的有效方法。或者你可以不使用数据类并创建一个普通类。

我认为它可能会起作用是这样的:

fun getData()

这完全允许你这样做:

typealias notNullType = MyData

data class Test(private val _value: MyData? = null) {
    val v: notNullType = _value as notNullType
    get() { return field }
}

这样做 ...我不认为“隐藏”fun play() { val t = Test(null) print(t.v) //see what I did? :-) } 可选是一个好主意。

答案 2 :(得分:0)

如果你像MyData?

那样投射它,那么它并不一定意味着MyData类为null

&#39; &#39;只是允许对象在实际变为null的实例中为null,以避免在运行时发生异常。

您可以让您的类可以为空,但它仍然可以包含您的数据。