2012-12-30 11 views
19

Jestem ciekawy - jaki jest sens generycznego typu U w deklaracji metody Traversable 's' foreach?Jaki jest sens rodzaju generycznego w foreach?

def foreach[U](f: A => U): Unit 

Ponieważ typ powrót Function1 jest kowariantna, dlaczego nie może być tak, że:

def foreach(f: A => Any): Unit 

?

+0

Nie mam czasu, aby wymyślić przykład, ale mocno podejrzewam, że pozwala inferencer typu ignorować 'foreach', jeśli chodzi o wnioskowanie typu zwrotu funkcji. Ale nie znam przypadku poza moją głową, gdzie by to miało znaczenie (tzn. Że "Any" nie dałoby takiego samego wniosku). –

Odpowiedz

9

Nie będąc Martin Odersky , Mogę tylko zgadywać :-) Patrząc na Scaladoc z foreach, widzę to:

/** Applies a function `f` to all elements of this $coll. 
    * 
    * @param f the function that is applied for its side-effect to every element. 
    *    The result of function `f` is discarded. 
    *    
    * @tparam U the type parameter describing the result of function `f`. 
    *    This result will always be ignored. Typically `U` is `Unit`, 
    *    but this is not necessary. 
    * 
    * @usecase def foreach(f: A => Unit): Unit 
    */ 

Tak więc typ zwrotu f nie ma znaczenia, a jego wynik jest zawsze odrzucany. To, według mnie, sugeruje, że użycie ogólnego rodzaju parametru tutaj w celu oznaczenia typu zwrotu jest jedynie subtelnością dokumentacji, mówiąc, że "typem zwrotu może być wszystko, naprawdę wszystko, co lubisz". Zważywszy, że typ zwrotny Any może sugerować (niektórym) czytelnikom pewnego rodzaju ograniczenie do typów funkcji mających zastosowanie tutaj.

Innym aspektem jest to, że Scala została bardzo świadomie zaprojektowana jako ogólna od podstaw. Tak więc - dla mnie - użycie ogólnego parametru typu jest zgodne z ogólną filozofią tego języka, przy jednoczesnym użyciu Any - choć technicznie użyteczne - byłoby zdecydowanie nietypowym podejściem, które byłoby sprzeczne z resztą języka.

-5

Może pozwolić Ci odziedziczyć po Traversable i wykorzystać wartość zwracaną U z f: A => U?

trait TraversableWithHandler[+A, E <: Option[Throwable]] extends Traversable[A] { 
    override def foreach[U](f: A => U): Unit 
    def handleError(t: E) 
} 

Na przykład jQuery, zwrot false od wewnątrz foreach odpowiada break, inaczej wartość jest continue.

Use Case

breakable { 
    List(1,2,3).foreach(_ match { 
    case 1 => println("ok") 
    case 2 => 
     println("Sort of, soft interrupt?") 
     return false 
    case 3 => break 
    }) 
} 

Ponieważ następny kod (równoległe), nigdy nie łamie (Stackless rozwiązanie Throwable wydaje nieidealne w tym przypadku?):

import scala.util.control.Breaks._ 

breakable { 
    (0 to 100).toList.par.foreach(_ match { 
    case n if (n <= 50) => 
     println("#" * 100) 
     try { break } catch { 
     case t: Throwable => println("" + t); break 
     } 
    case n if (n > 50) => 
     println("" + n) 
    case _ => "ok" 
    }) 
} 
+0

-1: Biorąc pod uwagę, że takty niestacjonarne są używane w taki sposób do sterowania przepływem w takich sytuacjach, i że posiadanie formalnej wartości zwracanej jest w tym przypadku bezużyteczne, jest to wysoce nieprawdopodobne. Dodatkowo, nie pokazujesz żadnych przypadków użycia. Nie mam pojęcia, jak wykorzystać powyższy podpis. –

+0

Byłoby to w przeciwieństwie do Scaladoc, który mówi: "Wynik funkcji" f "jest odrzucany." –

+5

Ta odpowiedź nie jest tylko błędna, ale może być bardzo myląca. Właśnie zmieniłeś nazwę parametru tak, aby cienie 'scala.Boolean' - zdecydowanie nie ograniczałeś w jakiś sposób metody zadeklarowanej w' Traversable'. –