Harika: “def x = 0” daki “def” nin amacı nedir?


180

Aşağıdaki kod parçasında ( Groovy Semantics Manual sayfasından alınmıştır ), ödevi neden anahtar kelimeyle önek def?

def x = 0
def y = 5

while ( y-- > 0 ) {
    println "" + x + " " + y
    x++
}

assert x == 5

defAnahtar kelime kaldırılabilir ve bu pasajı aynı sonuçları üretecektir. Peki anahtar kelimenin etkisidef nedir?

Yanıtlar:


278

Temel senaryolar için sözdizimsel şekerdir. "Def" anahtar sözcüğünü atlamak, değişkeni geçerli komut dosyasının bağlantılarına koyar ve groovy (çoğunlukla) genel olarak kapsamlı bir değişken gibi davranır:

x = 1
assert x == 1
assert this.binding.getVariable("x") == 1

Bunun yerine def anahtar sözcüğünü kullanmak, değişkeni komut dosyası bağlamalarına koymaz:

def y = 2

assert y == 2

try {
    this.binding.getVariable("y") 
} catch (groovy.lang.MissingPropertyException e) {
    println "error caught"
} 

Çıktılar: "hata yakalandı"

Daha büyük programlarda def anahtar sözcüğünün kullanılması, değişkenin bulunabileceği kapsamın tanımlanmasına ve kapsüllemenin korunmasına yardımcı olabileceğinden önemlidir.

Komut dosyanızda bir yöntem tanımlarsanız, kapsamda olmadığı için ana komut dosyasının gövdesinde "def" ile oluşturulan değişkenlere erişemez:

 x = 1
 def y = 2


public bar() {
    assert x == 1

    try {
        assert y == 2
    } catch (groovy.lang.MissingPropertyException e) {
        println "error caught"
    }
}

bar()

"hata yakalandı"

"Y" değişkeni işlevin kapsamında değildir. "x", değişkenin geçerli komut dosyasının bağlantılarını kontrol edeceği için kapsamdadır. Daha önce söylediğim gibi, bu, hızlı ve kirli komut dosyalarını yazmayı daha hızlı hale getirmek için sadece sözdizimsel şekerdir (genellikle bir astar).

Büyük komut dosyalarında iyi bir uygulama her zaman "def" anahtar sözcüğünü kullanmaktır, böylece tuhaf kapsam belirleme sorunlarıyla karşılaşmaz veya istemediğiniz değişkenlere müdahale etmezsiniz.


36

Ted'in cevabı senaryolar için mükemmeldir; Ben'in cevabı sınıflar için standarttır.

Ben'in dediği gibi, bunu "Nesne" olarak düşünün - ama sizi Nesne yöntemleriyle sınırlamaması çok daha havalı. Bunun ithalata ilişkin net etkileri vardır.

Örneğin bu kod parçasında FileChannel'i içe aktarmam gerekiyor

// Groovy imports java.io.* and java.util.* automatically
// but not java.nio.*

import java.nio.channels.*

class Foo {
    public void bar() {
        FileChannel channel = new FileInputStream('Test.groovy').getChannel()
        println channel.toString()
    }
}

new Foo().bar()

Örneğin Ama burada her şey sınıf yolunda olduğu sürece 'kanatlayabilirim'

// Groovy imports java.io.* and java.util.* automatically
// but not java.nio.*
class Foo {
    public void bar() {
        def channel = new FileInputStream('Test.groovy').getChannel()
        println channel.toString()
    }
}

new Foo().bar()

1
neden new FileInputStream('Test.groovy').getChannel()içe aktarma işlemini devre dışı bıraktınız ?
Alexander Suraphel

3
@AlexanderSuraphel "her şey sınıf yolunda olduğu sürece"
Hanno

30

Bu sayfaya göre , defbir tür adının yerine geçer ve yalnızca bir takma ad olarak düşünülebilir Object(yani, türü önemsemediğinizi belirtmek).


12

Bu tek senaryo ile ilgili olarak, pratik bir fark yoktur.

Ancak, "def" anahtar sözcüğü kullanılarak tanımlanan değişkenler yerel değişkenler, yani bu tek komut dosyasının yerel olarak kabul edilir. Önlerinde "def" bulunmayan değişkenler ilk kullanımda ciltleme olarak adlandırılır. Bağlamayı "ara" komut dosyalarında bulunması gereken değişkenler ve kapaklar için genel bir depolama alanı olarak düşünebilirsiniz.

Bu nedenle, iki komut dosyanız varsa ve bunları aynı GroovyShell ile yürütürseniz, ikinci komut dosyası, ilk komut dosyasında ayarlanan tüm değişkenleri "def" olmadan alabilir.


8

"Def" nin nedeni, harika bir değişken oluşturmayı planladığınızı söylemektir. Önemlidir çünkü asla kazara bir değişken oluşturmak istemezsiniz.

Komut dosyalarında biraz kabul edilebilir (Groovy komut dosyaları ve groovysh bunu yapmanıza izin verir), ancak üretim kodunda karşılaşabileceğiniz en büyük kötülüklerden biridir, bu yüzden tüm gerçek groovy kodunda def olan bir değişkeni tanımlamanız gerekir ( sınıf).

İşte neden kötü olduğuna dair bir örnek. Aşağıdaki kodu kopyalayıp groovysh'a yapıştırırsanız, bu (onaylama başarısız olmadan) çalışacaktır:

bill = 7
bi1l = bill + 3
assert bill == 7

Bu tür bir problemin bulunması ve düzeltilmesi çok zaman alabilir - Hayatınızda sadece bir kez ısırsanız bile, kariyeriniz boyunca değişkenleri binlerce kez açıkça belirtmekten daha fazla zamana mal olacaktır. Ayrıca, nerede beyan edildiği de gözle anlaşılıyor, tahmin etmek zorunda değilsiniz.

Önemsiz komut dosyalarında / konsol girişinde (harika konsol gibi) komut dosyasının kapsamı sınırlı olduğu için biraz kabul edilebilir. Bence harikaların bunu komut dosyalarında yapmanıza izin vermesinin tek nedeni, DSL'leri Ruby'nin yaptığı gibi desteklemektir (Bana sorarsanız kötü bir takas, ancak bazı insanlar DSL'leri sever)


5

Aslında yok aynı davranacağını düşünüyorum ...

sağ taraftaki genel olarak Groovy'nin değişkeni yazması için yeterli bilgi içerdiğinden Groovy değişkenleri hala TYPED bildirimi değil bildirimi gerektirir.

Def veya bir tür ile bildirmediğim bir değişken kullanmaya çalıştığımda, kodu içeren sınıfın bir üyesini kullandığımı varsaydığı için "Böyle bir özellik yok" hatası alıyorum.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.