Biorąc drogie funkcja:
scala> def s(i: Int): String = i match { case 0=>null case 1=>"" case 2=>"hi" }
s: (i: Int)String
myślę, że to jest łatwe do odczytania i wolny od napowietrznych, cf this in the wild:
scala> def q(i: Int) = s(i) match { case ""|null => "<empty>" case x => x }
q: (i: Int)String
scala> q(0)
res3: String = <empty>
scala> q(1)
res4: String = <empty>
scala> q(2)
res5: String = hi
Do moich oczach, to nie jest tak wyrazisty, nawet z minimalistycznym interpunkcyjne
scala> Option(s(0)) filterNot (_.isEmpty) getOrElse "<empty>"
res6: String = <empty>
Ponadto, kontrast koszt w anonfun
zajęć dla zamknięć oraz dodatkowe wywołania metody:
scala> :javap -
Size 1161 bytes
MD5 checksum 765f5f67b0c574252b059c8adfab1cf0
Compiled from "<console>"
[...]
9: getstatic #26 // Field scala/Option$.MODULE$:Lscala/Option$;
12: getstatic #31 // Field .MODULE$:L;
15: iconst_0
16: invokevirtual #35 // Method .s:(I)Ljava/lang/String;
19: invokevirtual #39 // Method scala/Option$.apply:(Ljava/lang/Object;)Lscala/Option;
22: new #41 // class $anonfun$1
25: dup
26: invokespecial #42 // Method $anonfun$1."<init>":()V
29: invokevirtual #48 // Method scala/Option.filterNot:(Lscala/Function1;)Lscala/Option;
32: new #50 // class $anonfun$2
35: dup
36: invokespecial #51 // Method $anonfun$2."<init>":()V
39: invokevirtual #55 // Method scala/Option.getOrElse:(Lscala/Function0;)Ljava/lang/Object;
42: checkcast #57 // class java/lang/String
45: putfield #17 // Field res6:Ljava/lang/String;
Wzór Dopasowanie jest ogólnie po prostu jeśli, w przeciwnym razie, mniejsze i szybsze (nawet biorąc pod uwagę, że nie jest to optymalizacja s == ""
do s.isEmpty
):
scala> :javap -r #q
public java.lang.String q(int);
flags: ACC_PUBLIC
Code:
stack=2, locals=5, args_size=2
0: getstatic #19 // Field $line3/$read$$iw$$iw$.MODULE$:L$line3/$read$$iw$$iw$;
3: iload_1
4: invokevirtual #22 // Method $line3/$read$$iw$$iw$.s:(I)Ljava/lang/String;
7: astore_3
8: ldc #24 // String
10: aload_3
11: invokevirtual #28 // Method java/lang/Object.equals:(Ljava/lang/Object;)Z
14: ifeq 22
17: iconst_1
18: istore_2
19: goto 33
22: aload_3
23: ifnonnull 31
26: iconst_1
27: istore_2
28: goto 33
31: iconst_0
32: istore_2
33: iload_2
34: ifeq 44
37: ldc #30 // String <empty>
39: astore 4
41: goto 47
44: aload_3
45: astore 4
47: aload 4
49: areturn
Ale zainspirowana inną odpowiedzią, nawet jeśli nigdy nie zabrałabym tego kodu do domu, żeby spotkać się z rodzicami (ponieważ niepoprawnie przelicza wartość "null"
, jeśli funkcja ta zwraca je - chociaż może to jest funkcja do tego), tutaj jest regex:
scala> def p(i: Int) = "" + s(i) replaceAll ("^null$|^$", "<empty>")
p: (i: Int)String
"" + s(i)
jest skrótem String.valueOf
, co oczywiście daje String "null"
o zerowej wartości odniesienia. Doceniam umiejętność SO nie tylko do generowania szybkich odpowiedzi na pytania, ale także do zachęcania do myślenia nieszablonowego.
Jeśli nie był to test isEmpty, można po prostu przejść do Option (getSomeString), aby przekonwertować go na Option [String]. Czy w praktyce otrzymujesz zarówno puste, jak i puste ciągi? –
Tak, niestety. – trustin