Ten dokument stanowi pełną definicję standardów Google dotyczących kodowania kodu źródłowego na Androida w języku programowania Kotlin. Plik źródłowy Kotlin jest opisany jako utworzony w stylu Google Android tylko wtedy, gdy jest zgodny z określonymi regułami.
Podobnie jak w przypadku innych przewodników poświęconych stylom programowania, omówione tu kwestie obejmują nie tylko kwestie estetyczne związane z formatowaniem, ale także inne typy konwencji czy standardów kodowania. W tym dokumencie skupiliśmy się jednak głównie na trudnych i uniwersalnych zasadach, których przestrzegamy, i unikamy udzielania rad, których nie da się jednoznacznie wyegzekwować (przez człowieka lub narzędzie).
Ostatnia aktualizacja: 6.09.2023 r.
Pliki źródłowe
Wszystkie pliki źródłowe muszą mieć kodowanie UTF-8.
Nazwy
Jeśli plik źródłowy zawiera tylko jedną klasę najwyższego poziomu, nazwa pliku powinna zawierać nazwę z uwzględnieniem wielkości liter oraz rozszerzenie .kt
. Jeśli plik źródłowy zawiera wiele deklaracji najwyższego poziomu, wybierz nazwę opisującą jego zawartość, zastosuj parametr PascalCase (akceptowalna, jeśli nazwa pliku jest liczbą mnogą), i dołącz rozszerzenie .kt
.
// MyClass.kt class MyClass { }
// Bar.kt class Bar { } fun Runnable.toBar(): Bar = // …
// Map.kt fun <T, O> Set<T>.map(func: (T) -> O): List<O> = // … fun <T, O> List<T>.map(func: (T) -> O): List<O> = // …
// extensions.kt fun MyClass.process() = // … fun MyResult.print() = // …
Znaki specjalne
Odstępy
Oprócz sekwencji zakończenia wiersza jedynym znakiem odstępu występującym w dowolnym miejscu w pliku źródłowym jest poziomy znak odstępu ASCII (0x20). Oznacza to, że:
- Wszystkie pozostałe znaki odstępu w literałach znaków i ciągach znaków korzystają ze zmiany znaczenia.
- Znaki tabulacji nie służą do wcięcia.
Specjalne sekwencje zmiany znaczenia
W przypadku każdego znaku ze specjalną sekwencją zmiany znaczenia (\b
, \n
, \r
, \t
, \'
, \"
, \\
i \$
) jest ona używana, a nie odpowiedniego Unicode (np. \u000a
).
Znaki spoza tabeli znaków ASCII
W przypadku pozostałych znaków spoza tabeli znaków ASCII może to być rzeczywisty znak Unicode (np. ∞
) lub odpowiadającego mu kodowania Unicode (np. \u221e
).
Wybór zależy od tego, co sprawia, że kod jest łatwiejszy do odczytania i zrozumienia.
Odradzamy stosowanie zmian w standardzie Unicode w dowolnej lokalizacji w przypadku znaków drukowanych. Zdecydowanie odradzamy też stosowanie ich w przypadku literałów i komentarzy w postaci ciągów znaków.
Przykład | Dyskusja |
---|---|
val unitAbbrev = "μs" |
Najlepsze: być jasne, nawet bez komentarza. |
val unitAbbrev = "\u03bcs" // μs |
Kiepsko: nie ma powodu, by stosować znak zmiany znaczenia zawierający drukowany znak. |
val unitAbbrev = "\u03bcs" |
Kiepsko: czytelnik nie ma pojęcia, co to jest. |
return "\ufeff" + content |
Dobrze: w przypadku znaków niedrukowalnych należy używać znaków zmiany znaczenia. W razie potrzeby dodaj komentarz. |
Struktura
Plik .kt
zawiera następujące elementy (w kolejności):
- Nagłówek dotyczący praw autorskich lub licencji (opcjonalnie)
- Adnotacje na poziomie pliku
- Instrukcja dotycząca pakietu
- Importuj wyciągi
- Deklaracje najwyższego poziomu
Każda z tych sekcji oddziela dokładnie 1 pusty wiersz.
Prawa autorskie / licencja
Jeśli w pliku znajduje się nagłówek dotyczący praw autorskich lub licencji, powinien on znajdować się na samej górze w komentarzu wielowierszowym.
/* * Copyright 2017 Google, Inc. * * ... */
Nie używaj komentarza w stylu KDoc ani komentarza z jednym wierszem.
/** * Copyright 2017 Google, Inc. * * ... */
// Copyright 2017 Google, Inc. // // ...
Adnotacje na poziomie pliku
Adnotacje z elementem docelowym typu „use-site” typu „file” znajdują się między dowolnym komentarzem w nagłówku a deklaracją pakietu.
Instrukcja dotycząca pakietu
Instrukcja pakietu nie podlega żadnym limitom kolumn i nigdy nie jest zawijana wierszy.
Importuj wyciągi
Instrukcje importowania klas, funkcji i właściwości są zgrupowane na jednej liście i posortowane według zbioru ASCII.
Importy symboli wieloznacznych (dowolnego typu) są niedozwolone.
Podobnie jak instrukcja dotycząca pakietu, instrukcje importu nie podlegają limitowi kolumn i nigdy nie są zawijane wierszem.
Deklaracje najwyższego poziomu
Plik .kt
może zadeklarować jeden lub więcej typów, funkcji, właściwości lub aliasów typów na najwyższym poziomie.
Zawartość pliku powinna dotyczyć jednego motywu. Może to być na przykład pojedynczy typ publiczny lub zbiór funkcji rozszerzeń wykonujących tę samą operację na wielu typach odbiorników. Niepowiązane deklaracje powinny znajdować się w osobnych plikach, a deklaracje publiczne w jednym pliku należy zminimalizować.
Liczby ani kolejność zawartości pliku nie ograniczają w sposób wyraźny.
Pliki źródłowe są zwykle odczytywane od góry do dołu, co oznacza, że kolejność powinna odzwierciedlać fakt, że deklaracje znajdujące się u góry będą informować o tych dalszych. Kolejność treści może być różna w zależności od pliku. Podobnie jeden plik może zawierać 100 właściwości, 10 kolejnych funkcji, a jeszcze jeden – pojedynczą klasę.
Ważne jest, aby w każdym pliku zastosowano pewną kolejność logiczna, którą osoba zarządzająca może wyjaśnić, jeśli pojawi się taka prośba. Na przykład nowe funkcje nie są po prostu dodawane na końcu pliku, ponieważ spowodowałoby to porządkowanie „chronologicznie wg daty dodania”, które nie jest porządkowaniem logicznym.
Określanie kolejności osób na zajęciach
Kolejność członków klasy jest zgodna z tymi samymi regułami co deklaracja najwyższego poziomu.
Formatowanie
Aparaty ortodontyczne
Nawiasy klamrowe nie są wymagane w przypadku gałęzi when
i wyrażeń if
, które mają nie więcej niż 1 gałąź else
i mieszczą się w jednym wierszu.
if (string.isEmpty()) return val result = if (string.isEmpty()) DEFAULT_VALUE else string when (value) { 0 -> return // … }
Nawiasy klamrowe są też wymagane w przypadku wszystkich instrukcji i wyrażeń if
, for
, when
oraz do
i while
, nawet jeśli treść jest pusta lub zawiera tylko jedną instrukcję.
if (string.isEmpty()) return // WRONG! if (string.isEmpty()) { return // Okay } if (string.isEmpty()) return // WRONG else doLotsOfProcessingOn(string, otherParametersHere) if (string.isEmpty()) { return // Okay } else { doLotsOfProcessingOn(string, otherParametersHere) }
Niepuste bloki
Nawiasy klamrowe są zgodne ze stylem Kernighana i Ritchiego („nawiasy egipskie”) w przypadku niepustych bloków i konstrukcji przypominających bloki:
- Brak podziału wiersza przed otwierającym nawiasem klamrowym.
- Podział wiersza po otwierającym nawiasie klamrowym.
- Podział wiersza przed zamykającym nawiasem klamrowym.
- Podział wiersza po zamykającym nawiasie klamrowym, tylko wtedy, gdy ten nawias kończy instrukcję lub kończy treść funkcji, konstruktora lub klasy nazwanej.
Na przykład po nawiasie kwadratowym nie ma podziału wiersza, jeśli po nim następuje
else
lub przecinek.
return Runnable { while (condition()) { foo() } } return object : MyClass() { override fun foo() { if (condition()) { try { something() } catch (e: ProblemException) { recover() } } else if (otherCondition()) { somethingElse() } else { lastThing() } } }
Poniżej znajdziesz kilka wyjątków dotyczących klas wyliczeniowych.
Puste bloki
Pusty blok lub konstrukcja przypominająca blok musi być w stylu K&R.
try { doSomething() } catch (e: Exception) {} // WRONG!
try { doSomething() } catch (e: Exception) { } // Okay
Wyrażenia
Warunek if/else
używany jako wyrażenie może pomijać nawiasy klamrowe tylko wtedy, gdy całe wyrażenie mieści się w jednym wierszu.
val value = if (string.isEmpty()) 0 else 1 // Okay
val value = if (string.isEmpty()) // WRONG! 0 else 1
val value = if (string.isEmpty()) { // Okay 0 } else { 1 }
Wcięcie
Za każdym razem, gdy otwierany jest nowy konstrukt blokowy lub blokowy, wcięcie zwiększa się o cztery odstępy. Gdy blok się zakończy, wcięcie zostanie przywrócone do poprzedniego poziomu. Poziom wcięcia dotyczy zarówno kodu, jak i komentarzy w całym bloku.
Jedna instrukcja w wierszu
Po każdej instrukcji następuje podział wiersza. Średniki nie są używane.
Zawijanie wierszy
Kolumna kodu może zawierać maksymalnie 100 znaków. Z wyjątkiem sytuacji opisanych poniżej, wiersze, które przekraczają ten limit, muszą być zawijane w sposób opisany poniżej.
Wyjątki:
- Wiersze, w których nie można przestrzegać limitu kolumn (np. długi adres URL w pliku KDoc)
- Wyciągi
package
iimport
- Wiersze poleceń w komentarzu, które można wycinać i wklejać w powłoce.
Gdzie się rozbić
Najważniejsza dyrektywa zawijania wierszy to: wolą łamać tekst na wyższym poziomie składni. Poza tym:
- Jeśli wiersz jest rozłączony w nazwie operatora lub funkcji infix, przerwa występuje po nazwie operatora lub funkcji infix.
- Jeśli linia jest przerywana na podstawie następujących symboli operatora, przerwa znajduje się przed tym symbolem:
- Separator kropek (
.
,?.
). - Dwa dwukropki odwołania do elementu (
::
).
- Separator kropek (
- Nazwa metody lub konstruktora pozostaje dołączona do otwierającego nawiasu (
(
), który następuje po nim. - Do poprzedzającego tokenu pozostaje przecinek (
,
). - Strzałka lambda (
->
) pozostaje dołączona do listy argumentów, która ją poprzedza.
Funkcje
Jeśli podpis funkcji nie mieści się w jednym wierszu, rozdziel każdą deklarację parametru na osobny wiersz. Parametry zdefiniowane w tym formacie powinny mieć pojedyncze wcięcie (+4). Nawias zamykający ()
) i typ zwrotu znajdują się w osobnym wierszu bez dodatkowego wcięcia.
fun <T> Iterable<T>.joinToString( separator: CharSequence = ", ", prefix: CharSequence = "", postfix: CharSequence = "" ): String { // … }
Funkcje wyrażeń
Jeśli funkcja zawiera tylko jedno wyrażenie, można ją przedstawić jako funkcję wyrażenia.
override fun toString(): String { return "Hey" }
override fun toString(): String = "Hey"
Właściwości
Jeśli inicjator usługi nie mieści się w jednym wierszu, rozdziel go po znaku równości (=
) i użyj wcięcia.
private val defaultCharset: Charset? = EncodingRegistry.getInstance().getDefaultCharsetForPropertiesFiles(file)
Właściwości deklarujące funkcję get
lub set
powinny znajdować się w osobnych wierszach z normalnym wcięciem (+4). Sformatuj je, stosując
takie same reguły jak funkcje.
var directory: File? = null set(value) { // … }Właściwości tylko do odczytu mogą używać krótszej składni, która mieści się w jednym wierszu.
val defaultExtension: String get() = "kt"
Odstęp
Pionowa
Pojawi się jeden pusty wiersz:
- Pomiędzy kolejnymi członkami klasy: właściwości, konstruktory, funkcje, zagnieżdżone klasy itp.
- Wyjątek: opcjonalny pusty wiersz między 2 kolejnymi właściwościami (bez żadnego innego kodu). Takie puste wiersze są wykorzystywane w razie potrzeby do tworzenia logicznych grup właściwości i kojarzenia ich z ich właściwościami bazowymi (jeśli występują).
- Wyjątek: poniżej znajdziesz puste linie między stałymi wyliczeniami.
- Między instrukcją w razie potrzeby, aby uporządkować kod w podsekcje logiczne.
- Opcjonalnie przed pierwszą instrukcją w funkcji, przed pierwszym elementem klasy lub po ostatnim elemencie klasy (ani nie zachęcam, ani nie zniechęcają).
- Zgodnie z wymaganiami innych sekcji tego dokumentu (takich jak sekcja Struktura).
Kilka następujących po sobie pustych wierszy jest dozwolony, ale nie jest to zalecane ani wymagane.
Pozioma
Pojedyncza spacja ASCII oprócz tych, które są wymagane przez reguły języka lub inne style stylu, a także literały, komentarze i dokument KDoc, występuje tylko w tych miejscach:
- Oddzielenie dowolnego zastrzeżonego słowa, np.
if
,for
lubcatch
, od otwartego nawiasu ((
), które następuje po nim w danym wierszu.// WRONG! for(i in 0..1) { }
// Okay for (i in 0..1) { }
- Oddzielenie dowolnego zastrzeżonego słowa, np.
else
lubcatch
, od zamykającego nawiasu klamrowego (}
), który poprzedza je w danym wierszu.// WRONG! }else { }
// Okay } else { }
-
Przed każdym otwartym nawiasem klamrowym (
{
).// WRONG! if (list.isEmpty()){ }
// Okay if (list.isEmpty()) { }
-
Po obu stronach dowolnego operatora binarnego.
// WRONG! val two = 1+1
// Okay val two = 1 + 1
Dotyczy to również tych symboli „operatorów”:- strzałka w wyrażeniu lambda (
->
).// WRONG! ints.map { value->value.toString() }
// Okay ints.map { value -> value.toString() }
-
dwa dwukropki (
::
) odwołania do członka.// WRONG! val toString = Any :: toString
// Okay val toString = Any::toString
-
separatora kropek (
.
).// WRONG it . toString()
// Okay it.toString()
-
operator zakresu (
..
).// WRONG for (i in 1 .. 4) { print(i) }
// Okay for (i in 1..4) { print(i) }
- strzałka w wyrażeniu lambda (
-
Przed dwukropkiem (
:
) tylko wtedy, gdy jest on używany w deklaracji klasy do określenia klasy podstawowej lub interfejsów albo w klauzuliwhere
na potrzeby ograniczeń ogólnych.// WRONG! class Foo: Runnable
// Okay class Foo : Runnable
// WRONG fun <T: Comparable> max(a: T, b: T)
// Okay fun <T : Comparable> max(a: T, b: T)
// WRONG fun <T> max(a: T, b: T) where T: Comparable<T>
// Okay fun <T> max(a: T, b: T) where T : Comparable<T>
-
Po przecinku (
,
) lub dwukropku (:
).// WRONG! val oneAndTwo = listOf(1,2)
// Okay val oneAndTwo = listOf(1, 2)
// WRONG! class Foo :Runnable
// Okay class Foo : Runnable
-
Po obu stronach podwójnego ukośnika (
//
) zaczyna się komentarz na końcu wiersza. Możesz wstawić kilka spacji, ale nie jest to wymagane.// WRONG! var debugging = false//disabled by default
// Okay var debugging = false // disabled by default
Ta reguła nigdy nie jest interpretowana jako wymagająca lub zabronionej dodatkowej przestrzeni na początku lub na końcu wiersza – ma zastosowanie tylko do przestrzeni wewnętrznej.
Konkretne konstrukcje
Klasy w liczbie
Wyliczenie bez funkcji i dokumentacji dotyczącej stałych wartości może być opcjonalnie sformatowane jako pojedynczy wiersz.
enum class Answer { YES, NO, MAYBE }
Gdy stałe w wyliczeniu są umieszczone w osobnych wierszach, pusty wiersz nie jest między nimi wymagany, chyba że definiują one treść.
enum class Answer { YES, NO, MAYBE { override fun toString() = """¯\_(ツ)_/¯""" } }
Klasy wyliczeniowe są klasami, więc mają zastosowanie wszystkie pozostałe reguły formatowania.
Adnotacje
Adnotacje o użytkowniku lub typie są umieszczane w oddzielnych wierszach bezpośrednio przed konstrukcją z adnotacjami.
@Retention(SOURCE) @Target(FUNCTION, PROPERTY_SETTER, FIELD) annotation class Global
Adnotacje bez argumentów można umieścić w jednym wierszu.
@JvmField @Volatile var disposable: Disposable? = null
Gdy dostępna jest tylko jedna adnotacja bez argumentów, można ją umieścić w tym samym wierszu co deklaracja.
@Volatile var disposable: Disposable? = null @Test fun selectAll() { // … }
Składni @[...]
można używać tylko w przypadku jawnego celu związanego z używaniem witryny i tylko do łączenia w jednym wierszu co najmniej 2 adnotacji bez argumentów.
@field:[JvmStatic Volatile] var disposable: Disposable? = null
Pośrednie zwroty lub typy usług
Jeśli treść funkcji wyrażenia lub inicjator właściwości jest wartością skalarną lub zwracany typ można łatwo wywnioskować z treści, można go pominąć.
override fun toString(): String = "Hey" // becomes override fun toString() = "Hey"
private val ICON: Icon = IconLoader.getIcon("/icons/kotlin.png") // becomes private val ICON = IconLoader.getIcon("/icons/kotlin.png")
Gdy tworzysz bibliotekę, zachowaj jawną deklarację typu, jeśli stanowi ona część publicznego interfejsu API.
Nazwy
Identyfikatory mogą zawierać tylko litery i cyfry z zestawu ASCII oraz (w nielicznych przypadkach wymienionych poniżej) podkreślenia. W ten sposób każda prawidłowa nazwa identyfikatora jest dopasowywana do wyrażenia regularnego \w+
.
Specjalne prefiksy i sufiksy, takie jak te w przykładach name_
, mName
, s_name
i kName
, nie są używane z wyjątkiem właściwości kopii zapasowej (patrz Właściwości kopii zapasowej).
Nazwy pakietów
Nazwy pakietów są zapisywane małymi literami, a kolejne słowa są po prostu połączone (bez znaków podkreślenia).
// Okay package com.example.deepspace // WRONG! package com.example.deepSpace // WRONG! package com.example.deep_space
Wpisz nazwy
Nazwy klas należy zapisywać w języku PascalCase i zwykle są to rzeczowniki lub frazy. np. Character
lub ImmutableList
. Nazwy interfejsów mogą też być rzeczownikami lub wyrażeniami rzeczownikowymi (np. List
), ale czasami mogą też być przymiotnikami lub wyrażeniami przymiotnikowymi (np. Readable
).
Nazwy klas testowych zaczynają się od nazwy testowanej klasy i kończą na Test
. Na przykład HashTest
lub HashIntegrationTest
.
Nazwy funkcji
Nazwy funkcji są zapisywane wielbłąda i zazwyczaj są czasownikami lub wyrażeniami typu czasowniki. np. sendMessage
lub stop
.
W nazwach funkcji testowych mogą występować podkreślenia, które rozdzielają logiczne składniki nazwy.
@Test fun pop_emptyStack() { // … }
Funkcje z adnotacjami @Composable
, które zwracają wartość Unit
, mają format PascalCased i nazywane jako rzeczowniki, jakby były typem.
@Composable fun NameTag(name: String) { // … }
Nazwy funkcji nie powinny zawierać spacji, bo nie jest to obsługiwane na każdej platformie (w szczególności nie jest to w pełni obsługiwane na Androidzie).
// WRONG! fun `test every possible case`() {} // OK fun testEveryPossibleCase() {}
Nazwy stałe
W nazwach stałych wykorzystuje się wyrażenie UPPER_SNAKE_CASE, czyli wielkie litery i rozdzielone podkreśleniami. Ale co to dokładnie jest stała?
Stałe to właściwości val
, które nie mają niestandardowej funkcji get
, których zawartość jest głęboko stała i które funkcje nie mają wykrywalnych efektów ubocznych. Obejmuje to typy stałe i stałe kolekcje typów stałych, a także skalary i ciągi znaków, jeśli są oznaczone jako const
. Jeśli dowolny obserwowany stan instancji może się zmienić, nie jest to stała. Samo zamiary niedokonywania
zmian w obiekcie to za mało.
const val NUMBER = 5 val NAMES = listOf("Alice", "Bob") val AGES = mapOf("Alice" to 35, "Bob" to 32) val COMMA_JOINER = Joiner.on(',') // Joiner is immutable val EMPTY_ARRAY = arrayOf()
Są to zwykle rzeczowniki lub frazy.
Wartości stałe można zdefiniować tylko w elemencie object
lub w deklaracji najwyższego poziomu. Wartości, które w przeciwnym razie spełniają wymaganie stałej, ale są zdefiniowane w elemencie class
, muszą mieć nazwę niestałą.
Stałe, które są wartościami skalarnymi, muszą korzystać z modyfikatora const
.
Nazwy niestałe
Nazwy niestałe zapisują się w języku CamlCase. Te ustawienia mają zastosowanie do właściwości instancji, właściwości lokalnych i nazw parametrów.
val variable = "var" val nonConstScalar = "non-const" val mutableCollection: MutableSet= HashSet() val mutableElements = listOf(mutableInstance) val mutableValues = mapOf("Alice" to mutableInstance, "Bob" to mutableInstance2) val logger = Logger.getLogger(MyClass::class.java.name) val nonEmptyArray = arrayOf("these", "can", "change")
Są to zwykle rzeczowniki lub frazy.
Właściwości kopii zapasowej
Jeśli potrzebna jest właściwość zapasowa, jej nazwa powinna być identyczna z nazwą rzeczywistej właściwości, chyba że jest poprzedzona znakiem podkreślenia.
private var _table: Map? = null val table: Map get() { if (_table == null) { _table = HashMap() } return _table ?: throw AssertionError() }
Wpisz nazwy zmiennych
Każda zmienna typu ma nazwę w jednym z dwóch stylów:
- Pojedyncza duża litera, po której może następować jedna cyfra (np.
E
,T
,X
,T2
) - Nazwa w formie używanej przez zajęcia z wielką literą
T
(np.RequestT
,FooBarT
).
Etui wielbłąd
Czasami istnieje więcej niż jeden rozsądny sposób na przekształcenie angielskiej frazy wielbłąda z użyciem wielkich liter, np. użycie akronimów lub nietypowych terminów, takich jak „IPv6” czy „iOS”. Aby poprawić przewidywalność, użyj poniższego schematu.
Zaczyna się od imienia i nazwiska w formie prozy:
- Przekonwertuj wyrażenie na zwykły kod ASCII i usuń apostrofy. Na przykład „algorytm Mullera” może zostać zmieniony na „algorytm Muellera”.
- Podziel wynik na słowa, dzieląc je na spacje i pozostałe znaki interpunkcyjne (zwykle łączniki). Zalecane: jeśli jakieś słowo ma już konwencjonalną wielkość liter wielbłąda, podziel to na części składowe (np. „AdWords” zostanie zmieniony na „słowa reklamowe”. Pamiętaj, że słowo „iOS” nie jest w pełni zapisane wielkimi literami i jest niezgodne z jakąkolwiek konwencją, więc ta rekomendacja nie ma zastosowania.
- Teraz wszystkie treści (w tym akronimy) wpisz małymi literami, a potem wykonaj jedną z tych czynności:
- Zaczynamy każde słowo wielką literą, aby zapisać je z użyciem wielkich liter.
- Zaczyna się wielkimi literami pierwszy znak każdego wyrazu, z wyjątkiem pierwszego, który zostanie użyty do zapisu wielbłąda.
- Na koniec połącz wszystkie słowa w jeden identyfikator.
Zwróć uwagę, że wielkość liter w pierwotnych słowach jest prawie całkowicie pomijana.
Formularz zgłoszeniowy | Dobrze | Nieprawidłowo |
---|---|---|
„XML Http Request” | XmlHttpRequest |
XMLHTTPRequest |
„nowy identyfikator klienta” | newCustomerId |
newCustomerID |
"wewnętrzny stoper" | innerStopwatch |
innerStopWatch |
„obsługuje IPv6 w iOS” | supportsIpv6OnIos |
supportsIPv6OnIOS |
„Importer YouTube” | YouTubeImporter |
YoutubeImporter * |
(* Dozwolone, ale niezalecane).
Dokumentacja
Formatowanie
Podstawowe formatowanie bloków KDoc wygląda w tym przykładzie:
/** * Multiple lines of KDoc text are written here, * wrapped normally… */ fun method(arg: String) { // … }
...lub w tym jednowierszowym przykładzie:
/** An especially short bit of KDoc. */
Zawsze akceptowana jest forma podstawowa. Formularz jednowierszowy można zastąpić, gdy cały blok KDoc (w tym znaczniki komentarzy) mieści się w jednym wierszu. Pamiętaj, że dzieje się tak tylko wtedy, gdy nie ma tagów blokujących, np. @return
.
Akapity
Między akapitami i przed grupą tagów blokowych (jeśli istnieje) jest wyświetlany jeden pusty wiersz, czyli wiersz zawierający tylko wyrównaną na początku gwiazdkę (*
).
Zablokuj tagi
Wszystkie standardowe „tagi blokujące” występują w takiej kolejności:
@constructor
, @receiver
, @param
, @property
, @return
,
@throws
, @see
i nigdy nie mają pustego opisu.
Jeśli tag blokowania nie mieści się w jednym wierszu, kolejne wiersze są wcięte o 4 spacje od pozycji znacznika @
.
Fragment podsumowania
Każdy blok KDoc zaczyna się od krótkiego fragmentu podsumowania. Ten fragment jest bardzo ważny: jest to jedyna część tekstu, która pojawia się w określonych kontekstach, takich jak indeksy klas i metod.
Jest to fragment, czyli wyrażenie rzeczownikowe lub wyrażenie czasownikowe, a nie całe zdanie.
Nie zaczyna się od „A `Foo` is a...
” ani „This method returns...
” ani też nie musi stanowić pełnego zdania, takiego jak „Save the record.
”.
Wykorzystanie
Minimalnie w przypadku każdego typu public
i każdego elementu public
lub protected
tego typu występuje KDoc, z kilkoma wyjątkami wymienionymi poniżej.
Wyjątek: funkcje, które nie wymagają wyjaśnienia
KDoc jest opcjonalny w przypadku „prostych, oczywistych” funkcji, takich jak getFoo
i właściwości takich jak foo
, w sytuacjach, gdy naprawdę nie warto powiedzieć niczego więcej, jak „Zwraca foo”.
Nie należy powoływać się na ten wyjątek po to, by usprawiedliwić pominięcie istotnych informacji, które przeciętny czytelnik powinien znać. Na przykład w przypadku funkcji o nazwie getCanonicalName
lub właściwości o nazwie canonicalName
nie pomijaj dokumentacji (z uzasadnieniem, że mówi ona tylko /** Returns the canonical name. */
), jeśli typowy czytelnik może nie wiedzieć, co oznacza termin „nazwa kanoniczna”.
Wyjątek: zastąpienia
Plik KDoc nie zawsze jest dostępny w metodzie, która zastępuje metodę nadrzędną.