在设计具有泛型

时间:2017-07-02 20:42:19

标签: scala functional-programming covariance contravariance

我正在学习函数式编程,并且我试图理解协方差和逆变概念。我现在的问题是:我真的不知道什么时候应该对一般类型应用协方差和逆变。在具体的例子中,是的,我可以确定。但总的来说,我不知道哪种一般规则。

例如,这里有一些我研究过的规则:

  • 如果泛型类型充当参数:使用逆变。 (1)
  • 如果泛型类型充当retrun值:使用协方差。 (2)

在学习这个概念时我所知道的一些语言也使用这些惯例。例如: in 关键字用于协方差(在Scala中为+)和 out 关键字用于逆变(在Scala中为 - )。 Point(1)很容易理解。但在第(2)点,我看到异常:

  • methodA(Iterator<A>) A应该是协方差
  • methodA(Comparator<A>) A应该是逆转。

所以这里的例外情况是:虽然两个案例都使用泛型类型作为输入,但一个应该是协方差,而另一个应该是逆变。我的问题是:在设计课程时,我们是否有任何一般规则来决定协方差/逆变。

由于

1 个答案:

答案 0 :(得分:2)

协方差和逆变就像是算术中数字的符号,当你在另一个中嵌入一个方差的位置时,组成是不同的。

比较

1] +(+a) = +a
2] -(+a) = -a
3] +(-a) = -a
4] -(-a) = +a

trait +[+A] { def make(): A } // Produces an A
trait -[-A] { def break(a: A) } // Consumes an A

1]
  // Produces an A after one indirection: x.makeMake().make()
  trait ++[+A] { def makeMake(): +[A] }
  +[+[A]] = +[A]
2]
  // Consumes an A through one indirection: x.breakMake(new +[A] { override def make() = a })
  trait -+[-A] { def breakMake(m: +[A]) }
  -[+[A]] = -[A]
3]
  // Consumes an A after one indirection: x.makeBreak().break(a)
  trait +-[-A] { def makeBreak(): -[A] }
  +[-[A]] = -[A]
4]
  // Produces an A through one indirection
  // Slightly harder to see than the others
  // x.breakBreak(new -[A] { override def break(a: A) = {
  //   you have access to an A here, so it's like it produced an A for you
  // }})
  trait --[+A] { def breakBreak(b: -[A]) }
  -[-[A]] = +[A]

所以当你有

def method(iter: Iterator[A])

整个方法参数处于逆变位置,A位于Iterator内的协变位置,但是-[+[A]] = -[A],所以A实际上是-A在此签名内的逆变位置,该类需要说A。这是有道理的,外部用户正在传递一堆def method(comp: Comparator[A]) s,所以它应该是逆变的。

同样,在

A

整个方法参数处于逆变位置,而Comparator位于-[-[A]] = +[A]内的逆变位置,因此您将它们组成A并看到A真的处于一个协变的位置。这也是有道理的。当您将Comparator传递到A时,外部用户可以控制它的作用,因此有点像将import csv from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.ui import WebDriverWait as wait csvrows = [] def get_css_sel(selector): posts = browser.find_elements_by_css_selector(selector) for post in posts: print(post.text) csvrows.append(post.text) browser = webdriver.Chrome(executable_path=r'//Users/Pranavtadepalli/Downloads/chromedriver') browser.get("https://icostats.com") wait(browser, 20).until(EC.presence_of_element_located((By.CSS_SELECTOR, "#app > div > div.container-0-16 > div.table-0-20 > div.tbody-0-21 > div:nth-child(2) > div:nth-child(8)"))) get_css_sel("#app > div > div.container-0-16 > div.table-0-20 > div.tableheader-0-50") #fetch header of table get_css_sel("#app > div > div.container-0-16 > div.table-0-20 > div.tbody-0-21 > div") #fetch rows of table new=[",".join(elem.split("\n")) for elem in csvrows] newfile=open("csvfile.csv",'r') newfile1=open("csvfile.csv",'w') newstuff=newfile.read() for elem in new: newfile1.write(elem+'\n') newfile1.close() newfile.close() 返回给他们。