Jest to bardzo często spotykana rzecz w D. To jak zakresy działają. Na przykład, najbardziej podstawowy typ zakresu - zakres wejściowy - musi mieć 3 funkcje:
bool empty(); //Whether the range is empty
T front(); // Get the first element in the range
void popFront(); //pop the first element off of the range
funkcje matrycy następnie użyć std.range.isInputRange
celu sprawdzenia, czy dany typ jest prawidłowy zakres. Na przykład, najbardziej podstawowe przeciążenie std.algorithm.find
wygląda
R find(alias pred = "a == b", R, E)(R haystack, E needle)
if (isInputRange!R &&
is(typeof(binaryFun!pred(haystack.front, needle)) : bool))
{ ... }
isInputRange!R
jest true
jeśli R
jest prawidłowy zakres wejściowy i is(typeof(binaryFun!pred(haystack.front, needle)) : bool)
jest true
jeśli pred
akceptuje haystack.front
i needle
i zwraca typ, który jest niejawnie zamienny do bool
. Tak więc to przeciążenie opiera się wyłącznie na statycznym pisaniu kaczek.
Co do samego isInputRange
, wygląda mniej więcej tak
template isInputRange(R)
{
enum bool isInputRange = is(typeof(
{
R r = void; // can define a range object
if (r.empty) {} // can test for empty
r.popFront(); // can invoke popFront()
auto h = r.front; // can get the front of the range
}));
}
Jest to tytułowa szablon, więc kiedy jest używany, to jest zastępowany symbolem z nazwy, która w tym przypadku jest enum typu bool
. I że bool
jest true
, jeśli typ wyrażenia jest inny niż void
. typeof(x)
wyniki w void
, jeśli wyrażenie jest nieprawidłowe; w przeciwnym razie jest to typ wyrażenia x
. I is(y)
wyniki w true
jeśli y
jest non-void
. Tak więc isInputRange
kończy się na true
, jeśli kod w kompilacji wyrażeń typeof
, i false
w przeciwnym razie.
Wyrażenie w isInputRange
sprawdza, można zadeklarować zmienną typu R
, że R
ma człon (czy to funkcja, zmienna, lub cokolwiek) o nazwie empty
który może być używany w warunkach, które R
posiada funkcję o nazwie popFront
, która nie przyjmuje żadnych argumentów, i że R
ma członka front
, który zwraca wartość. Jest to oczekiwane API z zakresu wejściowego, a wyrażenie wewnątrz typeof
skompiluje się, jeśli R
będzie podążać za tym API, a zatem isInputRange
będzie dla tego typu true
. W przeciwnym razie będzie to false
.
Standardowa biblioteka D's ma wiele takich tytułowych szablonów (zazwyczaj zwanych cechami) i intensywnie wykorzystuje je w swoich ograniczeniach szablonowych. std.traits
w szczególności ma ich sporo. Tak więc, jeśli chcesz więcej przykładów tego, jak takie cechy są napisane, możesz tam zajrzeć (chociaż niektóre z nich są dość skomplikowane). Wewnętrzne cechy takich cech nie zawsze są szczególnie ładne, ale ładnie zamykają typowanie kaczek, więc ograniczenia szablonów są znacznie bardziej zrozumiałe (byłyby dużo, dużo brzydsze, gdyby takie testy zostały w nich wstawione bezpośrednio).
To normalne podejście do typowania kaczych liter w D. To wymaga trochę praktyki, aby wymyślić, jak dobrze je napisać, ale jest to standardowy sposób, aby to zrobić i działa. Byli ludzie, którzy zasugerowali próbę wymyślenia czegoś podobnego do twojej sugestii, ale nic tak naprawdę nie pochodzi z tego, a takie podejście byłoby w rzeczywistości mniej elastyczne, co czyni go niedostosowanym do wielu cech (choć z pewnością można by z niego korzystać z podstawowymi). Niezależnie od tego podejście, które tu opisałem, jest obecnie standardowym sposobem.
Ponadto, jeśli nie wiesz zbyt wiele o zakresach, proponuję przeczytać this.
Czy próbujesz utworzyć jedną funkcję do obsługi wszystkich przypadków użycia? Myślę, że wymagałoby to [statycznego foreach] (http://d.puremagic.com/issues/show_bug.cgi?id=4085), ale nie jestem pewien. Może zadziała jakaś magia CTFE? Interesuje mnie również: http://www.digitalmars.com/d/archives/digitalmars/D/static_foreach_108369.html – tjameson
@tjameson Tak, wierzę, że dla powyższego przykładu musiałbyś przechodzić przez wszystkie metody zdefiniowane w twoim interfejsie 'struct w czasie kompilacji. Jestem jednak otwarty na inne sposoby osiągnięcia tego samego celu, jeśli istnieją. – Dan
D ma wrap i unwrap (http://dlang.org/phobos-prerelease/std_typecons.html#.wrap i http://dlang.org/phobos-prerelease/std_typecons.html#.unwrap) udostępnia funkcję podobną do Go's pisanie kaczek. – DejanLekic