Kotlin'deki sabitler - bunları oluşturmanın önerilen yolu nedir?


165

Kotlin'de sabit oluşturmak nasıl önerilir? Peki adlandırma kuralı nedir? Bunu belgelerde bulamadım.

companion object {
    //1
    val MY_CONST = "something"

    //2
    const val MY_CONST = "something"

    //3
    val myConst = "something"
}

Yoksa ...?


4
public static finalJava'daki bir alana karşılık gelen bir şey istiyorsanız const val, tamamlayıcı nesnenizde kullanın . Bir private static finalalan ve halka açık bir alıcı istiyorsanız val, tamamlayıcı nesnenizde kullanın .
Michael

2
İşte Kotlin'de
Micer

Ödemeye bu yazıyı . İlgili performans değiş tokuşlarıyla sabitlerinizi saklayabileceğiniz farklı yollara güzel bir genel bakış sunar.
firedrillsergeant

Yanıtlar:


132

Kotlin'de, sınıfta kullanılması gereken yerel sabitleri oluşturmak istiyorsanız, aşağıdaki gibi oluşturabilirsiniz.

val MY_CONSTANT = "Constants"

Ve java'da statik statik final gibi kotlin'de bir kamu sabiti oluşturmak istiyorsanız, bunu aşağıdaki gibi oluşturabilirsiniz.

companion object{

     const val MY_CONSTANT = "Constants"

}

3
Yeni bir dosya gibi ayrı bir dosyada nasıl kullanabilirim Constants.ktveya nasıl?
Naveed Abbas

2
sabitler için bir dosya kullanın. tüm sabitlerimi orada tut.
filthy_wizard

2
İhtiyacınız olmayan companion objectben @piotrpo cevap kabul tane olması gerektiğini düşünüyorum
Chiara

@Chiara tamamlayıcı nesne (ve onu çevreleyen sınıf), üst düzey bildirimlerin aksine bir ad alanı görevi görür. Her iki cevabın da duruma bağlı olarak mantıklı olabileceğini düşünüyorum.
jingx

@jingx evet, ihtiyacınız olan bir ad alanı eklemek için bir noktanız var. : +1:
Chiara

118

Tamamlayıcı nesneler kullanmaktan kaçının. Kaputun arkasında, alanların erişilebilir olması için alıcı ve ayarlayıcı örnek yöntemleri oluşturulur. Örnek yöntemlerini çağırmak, statik yöntemleri çağırmaktan teknik olarak daha pahalıdır.

public class DbConstants {
    companion object {
        val TABLE_USER_ATTRIBUTE_EMPID = "_id"
        val TABLE_USER_ATTRIBUTE_DATA = "data"
    }

Bunun yerine içindeki sabitleri tanımlayın object.

Önerilen uygulama :

object DbConstants {
        const val TABLE_USER_ATTRIBUTE_EMPID = "_id"
        const val TABLE_USER_ATTRIBUTE_DATA = "data"
}

ve bunlara küresel olarak şu şekilde erişin: DbConstants.TABLE_USER_ATTRIBUTE_EMPID


Tamamlayıcı nesne, nesnenin özel bir durumu değil mi? Bir nasıl const valbir refakatçi nesnede bir daha farklı olsun const valsıradan nesnede (yani sizin örnekler arasındaki tek fark, atlanmış olduğu görülmektedir constarkadaşı nesne durumda - eklerseniz const, örnekler aynı performansa sahip olmalıdır)
Erwin Bolwidt

1
@ErwinBolwidt Bence @ sudesh'in amacı, yapının tek amacı bazı sabit değerler için bir ad alanı sağlamak olduğunda, sınıf sarma-tamamlayıcı-nesne tasarımını kullanmamak gerektiğidir. Ancak yapınızın somutlaştırılabilir olması ve ayrıca birkaç const vals içermesi gerekiyorsa, a'nın companion objectdoğru olduğunu beyan etmek .
Ari Lacenski

7
@ErwinBolwidt: sudesh doğru, tamamlayıcı nesneler için oluşturulan bayt kodu başlık altında alıcıları ile ek nesne oluşturma içerir. Ayrıştırılmış kotlin örnekleri ile iyi bir açıklama için bkz. Blog.egorand.me/where-do-i-put-my-constants-in-kotlin
dominik

2
teşekkürler @dominik, bu çok ayrıntılı bir makale, bunu derinlemesine anlamak isteyen herkese tavsiye ederim, kotlin'in yetersiz bayt kodu ürettiği birçok durum var, jetbrains bu performansla ilgili birçok hatayı çözdü ... tartışmaya göz kulak olun .kotlinlang.org , bu gibi altta yatan pek çok husus hakkında bilgilendirileceksiniz.
sudesh

1
Bugün cevabınızdan çok şey öğrendim sudesh teşekkürler!
Rakhi Dhavale

34

Her şeyden önce , Kotlin'deki sabitler için adlandırma kuralı java ile aynıdır (örneğin: MY_CONST_IN_UPPERCASE).

Nasıl yaratmalıyım?

1. Üst seviye değeri olarak (önerilir)

Sen sadece kendi sınıf beyanı dışında const koymak zorunda .

İki olasılık : Sınıf dosyanızdaki sabitinizi beyan edin (sabitinizin sınıfınızla açık bir ilişkisi vardır)

private const val CONST_USED_BY_MY_CLASS = 1

class MyClass { 
    // I can use my const in my class body 
}

Bu küresel sabitin depolanacağı özel bir constants.kt dosyası oluşturun (Burada, sabitinizi projenizde yaygın olarak kullanmak istiyorsunuz):

package com.project.constants
const val URL_PATH = "https:/"

O zaman sadece ihtiyacınız olan yere aktarmanız gerekir:

import com.project.constants

MyClass {
    private fun foo() {
        val url = URL_PATH
        System.out.print(url) // https://
    }
}

2. Bunu bir tamamlayıcı nesnede (veya bir nesne bildiriminde) bildirin

Bu çok daha az temiz çünkü kaputun altında bayt kodu üretildiğinde işe yaramaz bir nesne yaratılır:

MyClass {
    companion object {
        private const val URL_PATH = "https://"
        const val PUBLIC_URL_PATH = "https://public" // Accessible in other project files via MyClass.PUBLIC_URL_PATH
    }
}

Bir const yerine val olarak bildirirseniz daha da kötüsü (derleyici işe yaramaz bir nesne + işe yaramaz bir işlev oluşturur):

MyClass {
    companion object {
        val URL_PATH = "https://"
    }
}

Not :

Kotlin'de, const sadece ilkel türleri tutabilir. Bir işlevi ona iletmek istiyorsanız, @JvmField ek açıklamasını eklemeniz gerekir. Derleme zamanında, genel statik son değişken olarak dönüştürülecektir. Ancak ilkel tipten daha yavaştır. Bundan kaçınmaya çalışın.

@JvmField val foo = Foo()

kabul edilen cevap bu olmalıdır. zaten böyle bir durumda: public static final Pattern REGEX_NOTEMPTY = Pattern.compile (". +") ????
Xan

24

Derleme zamanında bilinen değerler (ve bence) sabit olarak işaretlenebilir.

Adlandırma kuralları Java kurallarını izlemeli ve Java kodundan kullanıldığında düzgün bir şekilde görünür olmalıdır (tamamlayıcı nesnelerle elde etmek bir şekilde zordur, ancak yine de).

Uygun sabit beyanlar:

const val MY_CONST = "something"
const val MY_INT = 1

3
Naming conventions should follow Java ones- neden?
Jodimoro

3
Kotlin, birlikte çalışmayı düzgün hale getirmek için, aksi belirtilmedikçe, varsayılan olarak Java kurallarına uyar.
zsmb13

4
Belgede böyle belirtildi @Jodimoro kotlinlang.org/docs/reference/coding-conventions.html
Neil

2
@Neil, değil.
Jodimoro

13
Bu bağlantıda şöyle derlerIf in doubt, default to the Java Coding Conventions
Neil

16

Kotlin'de sabitleri bildirmek için bir sınıfa, nesneye veya eşlik eden bir nesneye ihtiyacınız yoktur. Tüm sabitleri içeren bir dosyayı (örneğin, Constants.kt dosyasını bildirebilir veya mevcut herhangi bir Kotlin dosyasının içine koyabilirsiniz) ve doğrudan dosyanın içindeki sabitleri bildirebilirsiniz. Derleme zamanında bilinen sabitler ile işaretlenmelidir const.

Yani, bu durumda, şöyle olmalıdır:

const val MY_CONST = "something"

ve sonra sabiti aşağıdakileri kullanarak içe aktarabilirsiniz:

import package_name.MY_CONST

Bu bağlantıya başvurabilirsiniz


13
Sabitler ilişkili oldukları sınıfta olmalıdır. Eğer bir 'Sabitler' dersi yaparsanız, sonunda yüzlerce sabiti sona erdireceksiniz. Pe: MAX_WIDTH, MAX_HEIGHT Screen sınıfında olmalı, böylece mantıksal olarak erişebilirsiniz: Screen.MAX_WIDTH ve Constant.SCREEN_MAX_WIDTH değerini Constant.SCR_MAX_W ve Constants.MAX_WIDTH değerlerini koymanız gerekmez çünkü NOBODY otomatik tamamlama için Ctrl + boşluğunu ittiklerinde yüzlerce / thousans satırını aşağı kaydırır. Cidden: yapma.
sürdürülemezliğe

1
@inigoD Sabiti tek bir yerde ya da sadece çocuklarda kullanırsanız doğrudur, ancak durum hiç de böyle değildir. Eğer sabiti belirsiz bir sınıfa koyarsanız, unutursanız veya bir kod tabanını devralmanız daha olasıdır, bunları çoğaltabilirsiniz. Veya onları nereye koyacağınız belli değil. Kaynak veya hedef? Bulması kolay birkaç sabit dosya oluşturabilirsiniz. Biri tercih anahtarları için, biri istek anahtarları için, biri görünüm sabitleri için, vb.
Herrbert74

1
@ Herrbert74 Üzgünüm ama seninle aynı fikirde değilim. Bazen hangisinin olduğunu bulmak zor olabilir, ancak sabit bir yer her zaman onunla daha ilgili olan sınıf olmalıdır. Onları daha sonra almak isterseniz rastgele bir rastgele dosyaya kaydetmek en iyi yol değildir ... Rastgele depolanmayacaklarını, ancak sabitlerin ilgili olduğu paketlerde olduğunu iddia edersiniz, ancak bu sadece bir mazerettir. onları ilgili oldukları sınıflara koymayın, sonunda, onların yeri ...
inigoD

4
Bir sabit gerçekten küreselse veya geniş bir kapsama sahipse ... tüm paketler arasında kullanılan bir ek açıklama değeri veya birden fazla Denetleyici tarafından getirilen bir Üstbilgi adı vb. Gibi durumlarda, "sabitler" oluşturmak tamamen kabul edilebilir. sınıf "olarak adlandırılır. Ancak, yalnızca belirli bağlamlarda kullanılan sabitler bu bağlamda kapsamlandırılmalı ve ilgili sınıfta bildirilmelidir.
Nefthys76

@ Nephthys76 Bir not olarak, " tüm paketler arasında kullanılan bir ek açıklama için bir değer gibi " için, sabit için en iyi yerin ek açıklama sınıfında olduğunu söyleyebilirim.
Lahana Salatası

8

Eğer const val valName = valValuesınıf adının önüne koyarsanız , bu şekilde bir

public static final YourClass.Ktpublic static finaldeğerleri olacak .

Kotlin :

const val MY_CONST0 = 0
const val MY_CONST1 = 1
data class MyClass(var some: String)

Java ayrıştırıldı:

public final class MyClassKt {
    public static final int MY_CONST0 = 0;
    public static final int MY_CONST1 = 1;
}
// rest of MyClass.java

Bu doğru mu? Herkes bu yöntem ile herhangi bir deneyimi var mı?
Scott Biggs

5
class Myclass {

 companion object {
        const val MYCONSTANT = 479
}

constanahtar kelimeyi kullanabileceğiniz veya @JvmFieldjava'nın statik son sabiti olmasını sağlayan iki seçeneğiniz vardır .

class Myclass {

     companion object {
           @JvmField val MYCONSTANT = 479
    }

@JvmFieldEk açıklamayı kullanırsanız, derledikten sonra sabit sizin için java dediğiniz şekilde konur.
Java'da dediğiniz gibi, derleyici koddaki refakatçi sabitini aradığınızda bunun sizin için yerini alacaktır.

Ancak, const anahtar sözcüğünü kullanırsanız, sabitin değeri satır içine alınır. Satır içi ile, gerçek değer derlendikten sonra kullanıldığı anlamına gelir.

özetlemek gerekirse derleyici sizin için ne yapar:

//so for @JvmField:

Foo var1 = Constants.FOO;

//and for const:

Foo var1 = 479

5

Kotlin statik ve sabit değer ve yöntem beyanı

object MyConstant {

@JvmField   // for access in java code 
val PI: Double = 3.14

@JvmStatic // JvmStatic annotation for access in java code
fun sumValue(v1: Int, v2: Int): Int {
    return v1 + v2
}

}

Her yerden erişim değeri

val value = MyConstant.PI
val value = MyConstant.sumValue(10,5)

1
global veya statik yöntem nasıl tanımlanır?
Samad Talukder

(: Int, v2: Int v1): Int {return v1 + v2} @SamadTalukder In Kotlin eğlenceli sumvalue olacak
Shomu

5

Gibi val, tanımlanmış değişkenler constanahtar kelime değişken değildir. Buradaki fark constderleme zamanında bilinen değişkenler için kullanılır.

Değişken bildirmek const, staticanahtar kelimeyi Java'da kullanmaya benzer .

Kotlin'de bir sabit değişkenin nasıl bildirileceğini görelim:

const val COMMUNITY_NAME = "wiki"

Ve Java ile yazılmış benzer kod:

final static String COMMUNITY_NAME = "wiki";

Yukarıdaki cevaplara ekleme -

@JvmField Kotlin derleyicisine bu özellik için alıcı / ayarlayıcı oluşturmamasını ve bir alan olarak göstermemesini bildirmek için kullanılabilir.

 @JvmField
 val COMMUNITY_NAME: "Wiki"

Statik alanlar

Adlandırılmış bir nesnede veya tamamlayıcı nesnede bildirilen kotlin özellikleri, söz konusu nesnede veya tamamlayıcı nesneyi içeren sınıfta statik destek alanlarına sahip olacaktır.

Genellikle bu alanlar özeldir, ancak aşağıdaki yollardan biriyle gösterilebilir:

  • @JvmField açıklama;
  • lateinit değiştirici;
  • const değiştirici.

Daha fazla ayrıntı burada - https://kotlinlang.org/docs/reference/java-to-kotlin-interop.html#instance-fields


4

Cevapların hiçbirinde bahsedilmeyen bir şey, kullanım yüküdür companion objects. Okumak gibi burada , refakatçi nesneler aslında nesneleri ve onları yaratan kaynakları tüketir. Ayrıca, sabitinizi her kullandığınızda birden fazla alıcı işlevinden geçmeniz gerekebilir. İhtiyacınız Hepsi bir kaç ilkel sabitler ise muhtemelen sadece daha iyi kullanarak kapalı olacak valbir olsun daha iyi bir performans ve önlemek companion object.

TL; DR; makalenin:

Tamamlayıcı nesne kullanmak aslında bu kodu döndürür

class MyClass {

    companion object {
        private val TAG = "TAG"
    }

    fun helloWorld() {
        println(TAG)
    }
}

Bu koda:

public final class MyClass {
    private static final String TAG = "TAG";
    public static final Companion companion = new Companion();

    // synthetic
    public static final String access$getTAG$cp() {
        return TAG;
    }

    public static final class Companion {
        private final String getTAG() {
            return MyClass.access$getTAG$cp();
        }

        // synthetic
        public static final String access$getTAG$p(Companion c) {
            return c.getTAG();
        }
    }

    public final void helloWorld() {
        System.out.println(Companion.access$getTAG$p(companion));
    }
}

Bu yüzden onlardan kaçınmaya çalışın.


3

yerel sabitler:

const val NAME = "name"

Global sabitler:

object MyConstants{
    val NAME = "name"
    val ID = "_id"
    var EMAIL = "email"
}

MyConstants.NAME dosyasına eriş


1

Kotlin'de sabitleri tanımlamanın birkaç yolu vardır,

Tamamlayıcı nesneyi kullanma

    companion object {
        const val ITEM1 = "item1"
        const val ITEM2 = "item2"
    }

herhangi bir sınıf içinde yukarıdaki tamamlayıcı nesne bloğunu kullanabilir ve bu bloğun içindeki tüm alanlarınızı tanımlayabilirsiniz. Ancak bu yaklaşımda bir sorun var, belgeler diyor ki,

tamamlayıcı nesnelerin üyeleri diğer dillerdeki statik üyeler gibi görünse de, çalışma zamanında bunlar gerçek nesnelerin örnek üyeleridir ve örneğin arabirimleri uygulayabilir.

Sabitinizi tamamlayıcı nesneyi kullanarak oluşturduğunuzda ve kodu çözülen bayt kodunu gördüğünüzde, aşağıdaki gibi bir şey görürsünüz ,

  ClassName.Companion Companion = ClassName.Companion.$$INSTANCE;
  @NotNull
  String ITEM1 = "item1";
  @NotNull
  String ITEM2 = "item2";

  public static final class Companion {
     @NotNull
     private static final String ITEM1 = "item1";
     @NotNull
     public static final String ITEM2 = "item2";

     // $FF: synthetic field
     static final ClassName.Companion $$INSTANCE;

     private Companion() {
     }

     static {
        ClassName.Companion var0 = new ClassName.Companion();
        $$INSTANCE = var0;
     }
  }

Burada , tamamlayıcı nesnelerin üyeleri diğer dillerdeki statik üyeler gibi görünse de, çalışma zamanında hala gerçek nesnelerin örnek üyeleri olan belgelerin söylediklerini kolayca görebilirsiniz .

Şimdi, aşağıdaki gibi tamamlayıcı nesneyi kullanmamız gerekmediği başka bir yol geliyor ,

object ApiConstants {
      val ITEM1: String = "item1"
 }

Yine, yukarıdaki snippet'in bayt kodunun decompiled sürümünü görürseniz, böyle bir şey bulacaksınız,

public final class ApiConstants {
     private static final String ITEM1 = "item1";

     public static final ApiConstants INSTANCE;

     public final String getITEM1() {
           return ITEM1;
      }

     private ApiConstants() {
      }

     static {
         ApiConstants var0 = new ApiConstants();
         INSTANCE = var0;
         CONNECT_TIMEOUT = "item1";
      }
    }

Şimdi yukarıdaki kod çözülmüş kodu görürseniz, her değişken için get yöntemi yaratıyor. Bu get yöntemi hiç gerekli değildir.

Bu olsun yöntemlerinin kurtulmak için kullanmanız gereken, const önce val aşağıda gibi,

object ApiConstants {
     const val ITEM1: String = "item1"
 }

Şimdi yukarıdaki snippet'in ayrıştırılmış kodunu görürseniz, kodunuz için en az arka plan dönüşümünü yaptığı için okumayı daha kolay bulacaksınız.

public final class ApiConstants {
    public static final String ITEM1 = "item1";
    public static final ApiConstants INSTANCE;

    private ApiConstants() {
     }

    static {
        ApiConstants var0 = new ApiConstants();
        INSTANCE = var0;
      }
    }

Bu sabitleri yaratmanın en iyi yoludur.


0

İlkel ve Dizgiler için:

/** The empty String. */
const val EMPTY_STRING = ""

Diğer durumlar için:

/** The empty array of Strings. */
@JvmField val EMPTY_STRING_ARRAY = arrayOfNulls<String>(0)

Misal:

/*
 * Copyright 2018 Vorlonsoft LLC
 *
 * Licensed under The MIT License (MIT)
 */

package com.vorlonsoft.android.rate

import com.vorlonsoft.android.rate.Constants.Utils.Companion.UTILITY_CLASS_MESSAGE

/**
 * Constants Class - the constants class of the AndroidRate library.
 *
 * @constructor Constants is a utility class and it can't be instantiated.
 * @since       1.1.8
 * @version     1.2.1
 * @author      Alexander Savin
 */
internal class Constants private constructor() {
    /** Constants Class initializer block. */
    init {
        throw UnsupportedOperationException("Constants$UTILITY_CLASS_MESSAGE")
    }

    /**
     * Constants.Date Class - the date constants class of the AndroidRate library.
     *
     * @constructor Constants.Date is a utility class and it can't be instantiated.
     * @since       1.1.8
     * @version     1.2.1
     * @author      Alexander Savin
     */
    internal class Date private constructor() {
        /** Constants.Date Class initializer block. */
        init {
            throw UnsupportedOperationException("Constants.Date$UTILITY_CLASS_MESSAGE")
        }

        /** The singleton contains date constants. */
        companion object {
            /** The time unit representing one year in days. */
            const val YEAR_IN_DAYS = 365.toShort()
        }
    }

    /**
     * Constants.Utils Class - the utils constants class of the AndroidRate library.
     *
     * @constructor Constants.Utils is a utility class and it can't be instantiated.
     * @since       1.1.8
     * @version     1.2.1
     * @author      Alexander Savin
     */
    internal class Utils private constructor() {
        /** Constants.Utils Class initializer block. */
        init {
            throw UnsupportedOperationException("Constants.Utils$UTILITY_CLASS_MESSAGE")
        }

        /** The singleton contains utils constants. */
        companion object {
            /** The empty String. */
            const val EMPTY_STRING = ""
            /** The empty array of Strings. */
            @JvmField val EMPTY_STRING_ARRAY = arrayOfNulls<String>(0)
            /** The part 2 of a utility class unsupported operation exception message. */
            const val UTILITY_CLASS_MESSAGE = " is a utility class and it can't be instantiated!"
        }
    }
}
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.