groovy:000> a1 = 'a'Jeśli chcielibyśmy stworzyć egzemplarz dla pojedynczego znaku (w Javie jako char lub java.lang.Character) wystarczy skorzystać z konstrukcji as char.
===> a
groovy:000> a2 = "a"
===> a
groovy:000> a1.class.name
===> java.lang.String
groovy:000> a2.class.name
===> java.lang.String
groovy:000> a1 = 'a'Przypominam, że nie istnieją typy proste w Groovy, a ich użycie to w rzeczywistości utworzenie egzemplarza typu opakowującego, np. dla char będzie to java.lang.Character.
===> a
groovy:000> a1.class.name
===> java.lang.String
groovy:000> a3 = a1 as char
===> a
groovy:000> a3.class.name
===> java.lang.Character
W ramach pojedynczych cudzysłowów możemy umieścić podwójne.
groovy:000> a4 = '"a"'Różnica między literałem a napisem jest w rozwiązywaniu wyrażeń ${}.
===> "a"
groovy:000> a4.class.name
===> java.lang.String
groovy:000> wartosc = 5Napisy są niezmienne (niemodyfikowalne, ang. immutable), więc zmiana ich wartości jest niemożliwa (chyba, że korzystają z domknięć zczytujących dane ze środowiska, ale sam napis jest niezmienny). Pamiętam, że rozgłaszałem coś zupełnie odwrotnego na ostatniej mojej prezentacji Groovy i Grails we Wrocławiu za co przepraszam. Tutaj nic się nie zmienia w stosunku do Javy.
===> 5
groovy:000> tekstJakoLiteral = 'Podano wartosc: ${wartosc}'
===> Podano wartosc: ${wartosc}
groovy:000> tekstJakoNapis = "Podano wartosc: ${wartosc}"
===> Podano wartosc: 5
Odczyt z literału bądź napisu jest poprzez symbol tablicowy [].
groovy:000> napis = "Ala ma kota"Specjalne znaki w napisach, np. $ (dolar) możemy pozbawić ich specjalności przez poprzedzenie ich ukośnikiem lewym '\' (ang. backslash), np. \$, albo przez skorzystanie z kolejnej konstrukcji do tworzenia specjalnych napisów przez użycie ukośnika prawego '/' (ang. slash).
===> Ala ma kota
groovy:000> napis[0]
===> A
groovy:000> napis[0..3]
===> Ala
groovy:000> dolary = 500Jak widać w przykładzie wyżej, Groovy rozwiązuje wartości zmiennych w napisach natychmiast podczas ich tworzenia (gorliwie), a opóźniony (leniwy) odczyt jest możliwy przez zastosowanie...domknięć (bezparametrowych).
===> 500
groovy:000>
groovy:000> napis = "Za 1 PLN placimy ${dolary}\$"
===> Za 1 PLN placimy 500$
groovy:000> napisUkosnikPrawy = /Za 1 PLN placimy ${dolary}$/
===> Za 1 PLN placimy 500$
groovy:000> dolary = 200
===> 200
groovy:000> napis
===> Za 1 PLN placimy 500$
groovy:000> napisUkosnikPrawy
===> Za 1 PLN placimy 500$
groovy:000> napisUkosnikPrawy = /Za 1 PLN placimy ${-> dolary}$/
===> Za 1 PLN placimy 200$
groovy:000> dolary = 10
===> 10
groovy:000> napisUkosnikPrawy
===> Za 1 PLN placimy 10$
Typem dla napisów z wyrażeniami ${} w Groovy jest GString (ang. Groovy string). Groovy inteligentnie przypisuje typ do naszych potrzeb.
groovy:000> (/napis/).classPołączenie GString i domknięć pokazuje jak Groovy traktuje domknięcia. Domknięcie to po prostu blok wykonywalny, który również może być przypisany do zmiennej, a użyty wprost będzie przypisany do zmiennej anonimowej.
===> class java.lang.String
groovy:000> zmienna = 5
===> 5
groovy:000> (/napis ze zmienna ${zmienna}/).class
===> class org.codehaus.groovy.runtime.GStringImpl
groovy:000> "kolejny napis".class
===> class java.lang.String
groovy:000> "kolejny napis, ale juz ze zmienna ${zmienna}".class
===> class org.codehaus.groovy.runtime.GStringImpl
groovy:000> wartosc = 4W Groovy napisy składające się z wielu linii budujemy z potrójnym podwójnym cudzysłowem i potrójnym pojedynczym cudzysłowem. Pięknie napisane, co? Innymi słowy, trzy razy piszemy pojedynczy cudzysłów, jeśli nie korzystamy z wyrażeń, a z nimi budujemy napis opakowany trzema podwójnymi.
===> 4
groovy:000> napis = "Wypiszemy napis wykonujac domkniecie ${-> wartosc}"
===> Wypiszemy napis wykonujac domkniecie 4
groovy:000> napis = "Wypiszemy napis wykonujac domkniecie $wartosc"
===> Wypiszemy napis wykonujac domkniecie 4
// definiuję domknięcie
groovy:000> domkn = {-> wartosc}
===> groovysh_evaluate$_run_closure1@f268de
// i buduję napis ze zmienną, która jest domknięciem
groovy:000> napis = "Wypiszemy napis wykonujac domkniecie $domkn"
===> Wypiszemy napis wykonujac domkniecie 4
groovy:000> napisBezZmiennychNaKilkaLinii = '''Zaczynam pisac,Przydatne chociażby do tworzenia plików XML, albo, jak to ujął autor, "Groovy even makes it easy to spam! (Hey, I'm just kidding.)" (str. 109). Żartowniś! :)
groovy:001> Linia 2
groovy:002> Linia 3 i kilka innych dodatkow, np. wyrazenie: $wartosc'''
===> Zaczynam pisac,
Linia 2
Linia 3 i kilka innych dodatkow, np. wyrazenie: $wartosc
groovy:000> napisZeZmiennymiNaKilkaLinii = """Linia 1
groovy:001> Linia 2
groovy:002> Linia 3 i zmienna $wartosc"""
===> Linia 1
Linia 2
Linia 3 i zmienna 4
W Groovy mamy przeciążanie operatorów, więc odejmowanie w napisach to wycinanie napisu. Dodano metodę minus() do typu String i możemy ciąć.
groovy:000> napis = "Ala ma kota"Możemy również iterować po alfabecie, co w połączeniu z napisami daje niesamowity efekt iterowania po napisach.
===> Ala ma kota
groovy:000> napis -= "ma"
===> Ala kota
groovy:000> for (str in 'ala'..'alg') {Groovy rozszerza klasę String o udostępnienie metod do pracy z wyrażeniami regularnymi. W ten sposób poza replaceFirst() oraz replaceAll() mamy ~ (tylda) (odpowiada funkcji negate()), który tworzy egzemplarz wzorca, co w połączeniu z napisami tworzonymi przez ukośniki przypomina Perla.
groovy:001> print "$str "
groovy:002> }
ala alb alc ald ale alf alg ===> null
groovy:000> wzorzec = ~/\w*/Nawet, jeśli nie zaczniemy pisać rozwiązań przemysłowych w Groovy, to do skryptów jest bezkonkurencyjny. Zamiast Perla możemy wykorzystać JVM z Groovy - w chwilach słabości zawsze możemy zejść na poziom Javy.
===> \w*
groovy:000> wzorzec.class.name
===> java.util.regex.Pattern
groovy:000> "Ala ma kota" =~ wzorzec
===> java.util.regex.Matcher[pattern=\w* region=0,11 lastmatch=]
groovy:000> matcher = "Ala ma kota" =~ wzorzec
===> java.util.regex.Matcher[pattern=\w* region=0,11 lastmatch=]
groovy:000> matcher.size()
===> 6
groovy:000> matcher[0]
===> Ala
groovy:000> matcher[1]
===>
groovy:000> for (wyraz in matcher) {
groovy:001> println "$wyraz"
groovy:002> }
Ala
ma
kota
===> null
Warto również przyjrzeć się różnicy między ==~ a =~. Pierwszy z nich sprawdza pełne dopasowanie, podczas gdy drugi jedynie częściowe.
groovy:000> matcher = "Ala ma kota" ==~ /ma/Niestety nie udało mi się napisać wyrażenia regularnego w stylu /\w{6}/ i nie wiem, dlaczego przykład poniżej zwraca false.
===> false
groovy:000> matcher = "Ala ma kota" =~ /ma/
===> java.util.regex.Matcher[pattern=ma region=0,11 lastmatch=]
groovy:000> matcher = "Ala ma kota" ==~ /Ala \w* kota/
===> true
groovy:000> matcher = "Ala ma kota" ==~ /\w{6}/Ma ktoś pomysł? Chętnie poznam rozwiązanie (i później będę się nim chwalił jak swoim :)). Na koniec przykład z książki (str. 113):
===> false
groovy:000> str = 'Groovy is groovy, really groovy'Jestem zauroczony!
===> Groovy is groovy, really groovy
groovy:000> (str =~ /groovy/).replaceAll('hip')
===> Groovy is hip, really hip
p.s. W komentarzu do wczorajszego wpisu Dokończenie rozdziału 5. o domknięciach z "Programming Groovy" pedro podniósł temat sprawdzenia, czy domknięcie jest faktycznie domknięciem. Odpowiedź w postaci przykładu.
groovy:000> def funkcja(domkniecie) {Dodałem sprawdzenie z wykorzystaniem instanceof.
groovy:001> if (domkniecie && domkniecie instanceof Closure) { return domkniecie() }
groovy:002> println "Parametr wejsciowy typu: ${domkniecie.class.name}"
groovy:003> }
===> true
groovy:000> funkcja { "Jestem domknieciem!" }
===> Jestem domknieciem!
groovy:000> funkcja "Jestem jedynie napisem"
Parametr wejsciowy typu: java.lang.String
===> null
Odnosnie przykladu
OdpowiedzUsuńmatcher = "Ala ma kota" ==~ /\w{6}/
to przeciez \w dopasowuje sie do znaku slowa (alphanumeric or _), a w tym tekscie nie ma ciaglej sekwencji 6 takich wlasnie znakow.
Sprobuj z \w{4} i zadziala
Próbowałem od 1 do 6 i nic. Przynajmniej będzie okazja popróbować się z wyrażeniami regularnymi poznając Groovy.
OdpowiedzUsuń==~ operator requires an exact match of the whole string.
OdpowiedzUsuńmatcher = "Ala" ==~ /\w{3}/
True
matcher = "Alakot" ==~ /\w{6}/
True
matcher = "Ala ma kota" =~ /\w{3}/
matcher.size() // 2
matcher = "Ala ma kota" =~ /\w{6}/
matcher.size() // 0
To wam powinno pomóc :)
Fajne są wyrażenia co? Mi szczególnie się podoba
OdpowiedzUsuńdef f = new File("c:/")
f.eachFileMatch(~/.*\.ini/){
println it
}
:)
Eksperymentowałem z domknięciami.
Na początek:
def x ={-> println "Hello world :)"}
def ifClosure = {domniemane, reakcja ->
if(domniemane != null && domniemane instanceof Closure ){
reakcja()
}
}
ifClosure(x){
println "Zaczynam zabawę"
x()
println "Koniec zabawy"
}
Proste i wiadomo co się stanie. Dobra a jeśli zrobimy tak:
Object.metaClass.ifClosure = {reakcja ->
if(delegate != null && delegate instanceof Closure ){
reakcja()
}else{
delegate
}
}
def y ={-> println "Hello world :)"}
y.ifClosure{
y()
}
println "abc".ifClosure{
":)"
}
No i teraz zgadnij jak to się zachowa? Można używać GroovyConsole ;)
Pozdrawiam,
Krzysztof Kowalczyk
"Ala ma kota" ==~ /(\w+\s?){3}/
OdpowiedzUsuń===> true
"Ala ma kota" ==~ /(\w+\s){2}\w+/
===> true
"Ala ma kota" ==~ /\w+ \w+ \w+/
===> true
Witam
OdpowiedzUsuńCo do przykładu z closure to nie zadziała dla:
funkcja null
Sprawdzanie closure!=null jest zbędne, ponieważ instanceof zwróci zawsze false jak null przyjdzie.
Wystarczy dać:
def funkcja(domkniecie) {
if (domkniecie instanceof Closure) {
return domkniecie()
}
println "Parametr wejsciowy typu: ${domkniecie?.class?.name}" // sprawdzanie null
}
funkcja 3
funkcja null
funkcja()
funkcja {
funkcja 44
}
Pozdrawiam
Andrzej Jóźwik