精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

從Java走進(jìn)Scala:Twitter API與Scala的交互

開(kāi)發(fā) 后端
Scitter 客戶機(jī)庫(kù)即將發(fā)布,但是還差最后一步。在這一期 面向 Java 開(kāi)發(fā)人員的 Scala 指南 中,Ted Neward 展示如何將更新、顯示和刪除功能添加到用于訪問(wèn) Twitter 的基于 Scala 的庫(kù)中。

本文是IBMDW上Ted Neward的Scala教學(xué)系列,本文是第16篇,標(biāo)題為《用 Scitter 更新 Twitter》。

51CTO編輯推薦:Scala編程語(yǔ)言專題

在撰寫(xiě)本文時(shí),夏季即將結(jié)束,新的學(xué)年就要開(kāi)始,Twitter 的服務(wù)器上不斷涌現(xiàn)出世界各地的網(wǎng)蟲(chóng)和非網(wǎng)蟲(chóng)們發(fā)布的更新。對(duì)于我們很多身在北美的人來(lái)說(shuō),從海灘聚會(huì)到足球,從室外娛樂(lè)到室內(nèi)項(xiàng)目,各種各樣的想法紛至沓來(lái)。為了跟上這種形勢(shì),是時(shí)候重訪 Scitter 這個(gè)用于訪問(wèn) Twitter 的 Scala 客戶機(jī)庫(kù)了。

如果 到目前為止 您一直緊隨 Scitter 的開(kāi)發(fā),就會(huì)知道,這個(gè)庫(kù)現(xiàn)在能夠利用各種不同的 Twitter API 查看用戶的好友、追隨者和時(shí)間線,以及其他內(nèi)容。但是,這個(gè)庫(kù)還不具備發(fā)布狀態(tài)更新的能力。在這最后一篇關(guān)于 Scitter 的文章中,我們將豐富這個(gè)庫(kù)的功能,增加一些有趣的內(nèi)容(終止和評(píng)價(jià))功能和重要方法 update()、show() 和 destroy()。在此過(guò)程中,您將了解更多關(guān)于 Twitter API 的知識(shí),它與 Scala 之間的交互如何,您還將了解如何克服兩者之間不可避免的編程挑戰(zhàn)。

注意,當(dāng)您看到本文的時(shí)候,Scitter 庫(kù)將位于一個(gè) 公共源代碼控制庫(kù) 中。當(dāng)然,我還將在本文中包括 源代碼,但是要知道,源代碼庫(kù)可能發(fā)生改變。換句話說(shuō),項(xiàng)目庫(kù)中的代碼與您在這里看到的代碼可能略有不同,或者有較大的不同。

POST 到 Twitter

到目前為止,我們的 Scitter 開(kāi)發(fā)主要集中于一些基于 HTTP GET 的操作,這主要是因?yàn)檫@些調(diào)用非常容易,而我想輕松切入 Twitter API。將 POSTDELETE 操作添加到庫(kù)中對(duì)于可見(jiàn)性來(lái)說(shuō)邁出了重要一步。到目前為止,可以在個(gè)人 Twitter 帳戶上運(yùn)行單元測(cè)試,而其他人并不知道您要干什么。但是,一旦開(kāi)始發(fā)送更新消息,那么全世界都將知道您要運(yùn)行 Scitter 單元測(cè)試。

如果繼續(xù)測(cè)試 Scitter,那么需要在 Twitter 上創(chuàng)建自己的 “測(cè)試” 帳戶。(也許用 Twitter API 編程的最大缺點(diǎn)是沒(méi)有任何合適的測(cè)試或模擬工具。)

目前的進(jìn)展

在開(kāi)始著手這個(gè)庫(kù)的新的 UPDATE 功能之前,我們來(lái)回顧一下到目前為止我們已經(jīng)創(chuàng)建的東西。(我不會(huì)提供完整的源代碼清單,因?yàn)?Scitter 已經(jīng)開(kāi)始變得過(guò)長(zhǎng),不便于全部顯示。但是,可以在閱讀本文時(shí),從另一個(gè)窗口查看 代碼。)

大致來(lái)說(shuō),Scitter 庫(kù)分為 4 個(gè)部分:

  • 來(lái)回發(fā)送的請(qǐng)求和響應(yīng)類型(UserStatus 等),包含在 API 中;它們被建模為 case 類。
  • OptionalParam 類型,同樣在 API 中的某些地方;也被建模為 case 類,這些 case 類繼承基本的 OptionalParam 類型。
  • Scitter 對(duì)象,用于通信基礎(chǔ)和對(duì) Twitter 的匿名(無(wú)身份驗(yàn)證)訪問(wèn)。
  • Scitter 類,存放一個(gè)用戶名和密碼,用于訪問(wèn)給定 Twitter 帳戶時(shí)進(jìn)行驗(yàn)證。

注意,在這最后一篇文章中,為了使文件大小保持在相對(duì)合理的范圍內(nèi),我將請(qǐng)求/響應(yīng)類型分開(kāi)放到不同的文件中。

終止和評(píng)價(jià)

那么,現(xiàn)在我們清楚了目標(biāo)。我們將通過(guò)實(shí)現(xiàn)兩個(gè) “只讀” Twitter API 來(lái)達(dá)到目標(biāo):end_session API(結(jié)束用戶會(huì)話)和 rate_limit_status API(描述在某一特定時(shí)段內(nèi)用戶帳戶還剩下多少可用的 post)。

end_session API 與它的同胞 verify_credentials 相似,也是一個(gè)非常簡(jiǎn)單的 API:只需用一個(gè)經(jīng)過(guò)驗(yàn)證的請(qǐng)求調(diào)用它,它將 “結(jié)束” 當(dāng)前正在運(yùn)行的會(huì)話。在 Scitter 類上實(shí)現(xiàn)它非常容易,如清單 1 所示:

清單 1. 在 Scitter 上實(shí)現(xiàn) end_session

				
package com.tedneward.scitter

{

  import org.apache.commons.httpclient._, auth._, methods._, params._

  import scala.xml._



  // ...

  class Scitter

  {

    /**

     *

     */

    def endSession : Boolean =

    {

      val (statusCode, statusBody) =

        Scitter.execute("http://twitter.com/account/end_session.xml",

          username, password)



      statusCode == 200

    }

  }

}

好吧,我失言了。也不是那么容易。

POST

和我們到目前為止用過(guò)的 Twitter API 中的其他 API 不一樣,end_session 要求傳入的消息是用 HTTP POST 語(yǔ)義發(fā)送的?,F(xiàn)在,Scitter.execute 方法做任何事情都是通過(guò) GET,這意味著需要將那些期望 GET 的 API 與那些期望 POST 的 API 區(qū)分開(kāi)來(lái)。

現(xiàn)在暫不考慮這一點(diǎn),另外還有一個(gè)明顯的變化:POST 的 API 調(diào)用還需將名稱/值對(duì)傳遞到 execute() 方法中。(記住,在其他 API 調(diào)用中,若使用 GET,則所有參數(shù)可以作為查詢參數(shù)出現(xiàn)在 URL 行;若使用 POST,則參數(shù)出現(xiàn)在 HTTP 請(qǐng)求的主體中。)在 Scala 中,每當(dāng)提到名稱/值對(duì),自然會(huì)想到 Scala Map 類型,所以在考慮建模作為 POST 一部分發(fā)送的數(shù)據(jù)元素時(shí),最容易的方法是將它們放入到一個(gè) Map[String,String] 中并傳遞。

例如,如果將一個(gè)新的狀態(tài)消息傳遞給 Twitter,需要將這個(gè)不超過(guò) 140 個(gè)字符的消息放在一個(gè)名稱/值對(duì) status 中,那么應(yīng)該如清單 2 所示:

清單 2. 基本 map 語(yǔ)法

				
val map = Map("status" -> message)

在此情況下,我們可以重構(gòu) Scitter.execute() 方法,使之用 一個(gè) Map 作為參數(shù)。如果 Map 為空,那么可以認(rèn)為應(yīng)該使用 GET 而不是 POST,如清單 3 所示:

清單 3. 重構(gòu) execute()

				
  private[scitter] def execute(url : String) : (Int, String) =

      execute(url, Map(), "", "")

    private[scitter] def execute(url : String, username : String,

	                             password : String) : (Int, String) =

      execute(url, Map(), username, password)

    private[scitter] def execute(url : String,

	                             dataMap : Map[String,String]) : (Int, String) =

      execute(url, dataMap, "", "")

    private[scitter] def execute(url : String, dataMap : Map[String,String],

                                 username : String, password : String) =

    {

      val client = new HttpClient()

      val method = 

        if (dataMap.size == 0)

        {

          new GetMethod(url)

        }

        else

        {

          var m = new PostMethod(url)


          val array = new Array[NameValuePair](dataMap.size)

          var pos = 0

          dataMap.elements.foreach { (pr) =>

            pr match {

              case (k, v) => array(pos) = new NameValuePair(k, v)

            }

            pos += 1

          }

          m.setRequestBody(array)

          

          m

        }


      method.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, 

        new DefaultHttpMethodRetryHandler(3, false))

        

      if ((username != "") && (password != ""))

      {

        client.getParams().setAuthenticationPreemptive(true)

        client.getState().setCredentials(

          new AuthScope("twitter.com", 80, AuthScope.ANY_REALM),

            new UsernamePasswordCredentials(username, password))

      }

      

      client.executeMethod(method)

      

      (method.getStatusLine().getStatusCode(), method.getResponseBodyAsString())

    }

execute() 方法最大的變化是引入了 Map[String,String] 參數(shù),以及與它的大小有關(guān)的 “if” 測(cè)試。該測(cè)試決定是處理 GET 請(qǐng)求還是 POST 請(qǐng)求。由于 Apache Commons HttpClient 要求 POST 請(qǐng)求的主體放在 NameValuePairs 中,因此我們使用 foreach() 調(diào)用遍歷 map 的元素。我們以二元組 pr 的形式傳入 map 的鍵和值,并將它們分別提取到本地綁定變量 kv,然后使用這些值作為 NameValuePair 構(gòu)造函數(shù)的構(gòu)造函數(shù)參數(shù)。

我們還可以使用 PostMethod 上的 setParameter(name, value) API 更輕松地做這些事情。出于教學(xué)的目的,我選擇了清單 3 中的方法:以表明 Scala 數(shù)組和 Java 數(shù)組一樣,仍然是可變的,即使數(shù)組引用被標(biāo)記為 val 仍是如此。記住,在實(shí)際代碼中,對(duì)于每個(gè) (k,v) 元組,使用 PostMethod 上的 setParameter(name, value) 方法要好得多。

還需注意,對(duì)于 if/else 返回的 “method” 對(duì)象的類型,Scala 編譯器會(huì)進(jìn)行 does the right thing 類型推斷。由于 Scala 可以看到 if/else 返回的是 GetMethod 還是 PostMethod 對(duì)象,它會(huì)選擇最接近的基本類型 HttpMethodBase 作為 “method” 的返回類型。這也意味著,在 execute() 方法的其余部分中,HttpMethodBase 中的任何不可用方法都是不可訪問(wèn)的。幸運(yùn)的是,我們不需要它們,所以至少現(xiàn)在沒(méi)有問(wèn)題。

清單 3 中的實(shí)現(xiàn)的背后還潛藏著最后一個(gè)問(wèn)題,這個(gè)問(wèn)題是由這樣一個(gè)事實(shí)引起的:我選擇了使用 Map 來(lái)區(qū)分 execute() 方法是處理 GET 操作,還是處理 POST 操作。如果還需要使用其他 HTTP 動(dòng)作(例如 PUTDELETE),那么將不得不再次重構(gòu) execute()。到目前為止,還沒(méi)有這樣的問(wèn)題,但是今后要記住這一點(diǎn)。

測(cè)試

在實(shí)施這樣的重構(gòu)之前,先運(yùn)行 ant test,以確保原有的所有基于 GET 的請(qǐng)求 API 仍可使用 — 事實(shí)確實(shí)如此。(這里假設(shè)生產(chǎn) Twitter API 或 Twitter 服務(wù)器的可用性沒(méi)有變化)。一切正常(至少在我的計(jì)算機(jī)上是這樣),所以實(shí)現(xiàn)新的 execute() 方法就非常容易:

清單 4. Scitter v0.3: endSession

				
  def endSession : Boolean =

    {

      val (statusCode, statusBody) =

        Scitter.execute("http://twitter.com/account/end_session.xml",

          Map("" -> ""), username, password)


      statusCode == 200

    }

這實(shí)在是再簡(jiǎn)單不過(guò)了。

接下來(lái)要做的是實(shí)現(xiàn) rate_limit_status API,它有兩個(gè)版本,一個(gè)是經(jīng)過(guò)驗(yàn)證的版本,另一個(gè)是沒(méi)有經(jīng)過(guò)驗(yàn)證的版本。我們將該方法實(shí)現(xiàn)為 Scitter 對(duì)象和 Scitter 類上的 rateLimitStatus,如清單 5 所示:

清單 5. Scitter v0.3: rateLimitStatus

				
package com.tedneward.scitter

{

  object Scitter

  {

    // ...

	

    def rateLimitStatus : Option[RateLimits] =

    {

      val url = "http://twitter.com/account/rate_limit_status.xml"

      val (statusCode, statusBody) =

        Scitter.execute(url)

      if (statusCode == 200)

      {

        Some(RateLimits.fromXml(XML.loadString(statusBody)))

      }

      else

      {

        None

      }

    }

  }

  

  class Scitter

  {

    // ...

	

    def rateLimitStatus : Option[RateLimits] =

    {

      val url = "http://twitter.com/account/rate_limit_status.xml"

      val (statusCode, statusBody) =

        Scitter.execute(url, username, password)

      if (statusCode == 200)

      {

        Some(RateLimits.fromXml(XML.loadString(statusBody)))

      }

      else

      {

        None

      }

    }

  }

}

我覺(jué)得還是很簡(jiǎn)單。

更新

現(xiàn)在,有了新的 POST 版本的 HTTP 通信層,我們可以來(lái)處理 Twitter API 的中心:update 調(diào)用。毫不奇怪,需要一個(gè) POST,并且至少有一個(gè)參數(shù),即 status。

status 參數(shù)包含要發(fā)布到認(rèn)證用戶的 Twitter 提要的不超過(guò) 140 個(gè)字符的消息。另外還有一個(gè)可選參數(shù):in_reply_to_status_id,該參數(shù)提供另一個(gè)更新的 id,執(zhí)行了 POST 的更新將回復(fù)該更新。

update 調(diào)用差不多就是這樣了,如清單 6 所示:

清單 6. Scitter v0.3: update

				
package com.tedneward.scitter

{

  class Scitter

  {

    // ...


    def update(message : String, options : OptionalParam*) : Option[Status] =

    {

      def optionsToMap(options : List[OptionalParam]) : Map[String, String]=

      {

        options match

        {

          case hd :: tl =>

            hd match {

              case InReplyToStatusId(id) =>

                Map("in_reply_to_status_id" -> id.toString) ++ optionsToMap(tl)

              case _ =>

                optionsToMap(tl)

            }

          case List() => Map()

        }

      }

      
      val paramsMap = Map("status" -> message) ++ optionsToMap(options.toList)


      val (statusCode, body) =

        Scitter.execute("http://twitter.com/statuses/update.xml", 
           paramsMap, username, password)

      if (statusCode == 200)

      {

        Some(Status.fromXml(XML.loadString(body)))

      }

      else

      {

        None

      }

    }

  }

}

也許這個(gè)方法中最 “不同” 的部分就是其中定義的嵌套函數(shù) — 與使用 GET 的其他 Twitter API 調(diào)用不同,Twitter 期望傳給 POST 的參數(shù)出現(xiàn)在執(zhí)行 POST 的主體中,這意味著在調(diào)用 Scitter.execute() 之前需要將它們轉(zhuǎn)換成 Map 條目。但是,默認(rèn)的 Map(來(lái)自 scala.collections.immutable)是不可變的,這意味著可以組合 Map,但是不能將條目添加到已有的 Map 中。

解決這個(gè)小難題的最容易的方法是遞歸地處理傳入的 OptionalParam 元素的列表(實(shí)際上是一個(gè) Array[])。我們將每個(gè)元素拆開(kāi),將它轉(zhuǎn)換成各自的 Map 條目。然后,將一個(gè)新的 Map(由新創(chuàng)建的 Map 和從遞歸調(diào)用返回的 Map 組成)返回到 optionsToMap。

然后,將 OptionalParamArray[] 傳遞到 optionsToMap 嵌套函數(shù)。然后,將返回的 Map 與我們構(gòu)建的包含 status 消息的 Map 連接起來(lái)。最后,將新的 Map 和用戶名、密碼一起傳遞給 Scitter.execute() 方法,以傳送到 Twitter 服務(wù)器。

隨便說(shuō)一句,所有這些任務(wù)需要的代碼并不多,但是需要更多的解釋,這是比較優(yōu)雅的編程方式。

潛在的重構(gòu)

理論上,傳給 update 的可選參數(shù)與傳給其他基于 GET 的 API 調(diào)用的可選參數(shù)將受到同等對(duì)待;只是結(jié)果的格式有所不同(結(jié)果是用于 POST 的名稱/值對(duì),而不是用于 URL 的名稱/值對(duì))。

如果 Twitter API 需要其他 HTTP 動(dòng)作支持(PUT 和/或 DELETE 就是可能需要的動(dòng)作),那么總是可以將 HTTP 參數(shù)作為特定參數(shù) — 也許又是一組 case 類 — 并讓 execute() 以一個(gè) HTTP 動(dòng)作、URL、名稱/值對(duì)的 map 以及(可選)用戶名/密碼作為 5 個(gè)參數(shù)。然后,必要時(shí)可以將可選參數(shù)轉(zhuǎn)換成一個(gè)字符串或一組 POST 參數(shù)。這些內(nèi)容只需記在腦中就行了。

顯示

show 調(diào)用接受要檢索的 Twitter 狀態(tài)的 id,并顯示 Twitter 狀態(tài)。和 update 一樣,這個(gè)方法非常簡(jiǎn)單,無(wú)需再作說(shuō)明,如清單 7 所示:

清單 7. Scitter v0.3: show

				
package com.tedneward.scitter

{

  class Scitter

  {

    // ...

	

    def show(id : Long) : Option[Status] =

    {

      val (statusCode, body) =

        Scitter.execute("http://twitter.com/statuses/show/" + id + ".xml",

		  username, password)

      if (statusCode == 200)

      {

        Some(Status.fromXml(XML.loadString(body)))

      }

      else

      {

        None

      }

    }

  }

}

還有問(wèn)題嗎?

另一種顯示方法

如果想再試一下模式匹配,那么可以看看清單 8 中是如何以另一種方式編寫(xiě) show() 方法的:

清單 8. Scitter v0.3: show redux

				
package com.tedneward.scitter

{

  class Scitter

  {

    // ...

	

    def show(id : Long) : Option[Status] =

    {

      Scitter.execute("http://twitter.com/statuses/show/" + id + ".xml", 
          username, password) match

      {

        case (200, body) =>

          Some(Status.fromXml(XML.loadString(body)))

        case (_, _) =>

          None

      }

    }

  }

}

這個(gè)版本比起 if/else 版本是否更加清晰,這很大程度上屬于審美的問(wèn)題,但公平而論,這個(gè)版本也許更加簡(jiǎn)潔。(很可能查看代碼的人看到 Scala 的 “函數(shù)” 部分越多,就認(rèn)為這個(gè)版本越吸引人。)

但是,相對(duì)于 if/else 版本,模式匹配版本有一個(gè)優(yōu)勢(shì):如果 Twitter 返回新的條件(例如不同的錯(cuò)誤條件或來(lái)自 HTTP 的響應(yīng)代碼),那么模式匹配版本在區(qū)分這些條件時(shí)可能更清晰。例如,如果某天 Twitter 決定返回 400 響應(yīng)代碼和一條錯(cuò)誤消息(在主體中),以表明某種格式錯(cuò)誤(也許是沒(méi)有正確地重新 Tweet),那么與 if/else 方法相比,模式匹配版本可以更輕松(清晰)地同時(shí)測(cè)試響應(yīng)代碼和主體的內(nèi)容。

還應(yīng)注意,我們還可以使用清單 8 中的方式創(chuàng)建一些局部應(yīng)用的函數(shù),這些函數(shù)只需要 URL 和參數(shù)。但是,坦白說(shuō),這是一種自找麻煩的解放方案,所以我不會(huì)采用。

撤銷

我們還想讓 Scitter 用戶可以撤銷剛才執(zhí)行的動(dòng)作。為此,需要一個(gè) destroy 調(diào)用,它將刪除已發(fā)布的 Twitter 狀態(tài),如清單 9 所示:

清單 9. Scitter v0.3: destroy

				
package com.tedneward.scitter

{

  class Scitter

  {

    // ...

	

    def destroy(id : Long) : Option[Status] =

    {

      val paramsMap = Map("id" -> id.toString())

    

      val (statusCode, body) =

        Scitter.execute("http://twitter.com/statuses/destroy/" + id.toString() + ".xml",

          paramsMap, username, password)

      if (statusCode == 200)

      {

        Some(Status.fromXml(XML.loadString(body)))

      }

      else

      {

        None

      }

    }

    def destroy(id : Id) : Option[Status] =

      destroy(id.id.toLong)

  }

}

有了這些東西,我們可以考慮將這個(gè) Scitter 客戶機(jī)庫(kù)作為 “alpha” 版,至少實(shí)現(xiàn)一個(gè)簡(jiǎn)單的 Scitter 客戶機(jī)。(按照慣例,這個(gè)任務(wù)就留給您來(lái)完成,作為一項(xiàng) “讀者練習(xí)”。)

結(jié)束語(yǔ)

編寫(xiě) Scitter 客戶機(jī)庫(kù)是一項(xiàng)有趣的工作。雖然不能說(shuō) Scitter 已經(jīng)可以完全用于生產(chǎn),但是它絕對(duì)足以用于實(shí)現(xiàn)簡(jiǎn)單的、基于文本的 Twitter 客戶機(jī),這意味著它已經(jīng)可以投入使用了。要發(fā)現(xiàn)什么人可以使用它,哪些特性是需要的,從而使之變得更有用,最好的方法就是將它向公眾發(fā)布。

我已經(jīng)將本文和之前關(guān)于 Scitter 的文章中的代碼作為第一個(gè)修訂版提交到 Google Code 上的 Scitter 項(xiàng)目主頁(yè)。歡迎下載和試用這個(gè)庫(kù),并告訴我您的想法。同時(shí)也歡迎提供 bug 報(bào)告、修復(fù)和建議。

您也無(wú)需受我的代碼庫(kù)的束縛。見(jiàn)證了之前三篇文章中進(jìn)行的 Scitter 開(kāi)發(fā),您應(yīng)該對(duì) Twitter API 的使用有很好的理解。如果對(duì)于使用該 API 有不同的想法,那么盡管去做:拋開(kāi) Scitter,構(gòu)建自己的 Scala 客戶機(jī)庫(kù)。畢竟,做做這些內(nèi)部項(xiàng)目也是挺有樂(lè)趣的。

現(xiàn)在,我們要向 Scitter 揮手告別,開(kāi)始尋找新的用 Scala 解決的項(xiàng)目。愿您從中找到樂(lè)趣,如果發(fā)現(xiàn)了用 Scala 編程的工作,別忘了告訴我!

責(zé)任編輯:yangsai 來(lái)源: IBMDW
相關(guān)推薦

2009-08-21 16:17:25

ScalaTwitter API

2009-09-28 11:01:39

從Java走進(jìn)Scal

2009-02-04 17:32:03

ibmdwJavaScala

2009-06-17 11:44:22

Scala控制結(jié)構(gòu)

2009-06-16 17:54:38

Scala類語(yǔ)法語(yǔ)義

2009-07-15 10:14:25

Scala并發(fā)性

2009-10-14 11:14:38

ScitterScalaTwitter

2009-09-09 10:50:55

Scala例子Scala與Java

2009-06-16 17:09:17

Scala面向?qū)ο?/a>函數(shù)編程

2009-08-14 11:35:01

Scala Actor

2009-06-17 13:57:25

Scala元組數(shù)組

2009-06-17 13:26:06

scala繼承模型

2009-06-19 10:51:39

Scalapackage訪問(wèn)修飾符

2009-06-15 15:33:13

ScalaTwitter

2009-08-27 12:00:40

ibmdwJava

2009-06-19 11:13:47

Scalacase類模式匹配

2009-07-08 12:43:59

Scala ServlScala語(yǔ)言

2009-06-19 11:42:09

Scala計(jì)算器解析

2009-09-15 18:27:59

equals實(shí)現(xiàn)canEqualScala

2010-09-14 15:34:41

Scala
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

小说区视频区图片区| 日本a级片电影一区二区| 亚洲天堂伊人网| 羞羞的网站在线观看| 国产高清一区日本| 992tv在线成人免费观看| 丰满少妇一区二区| 亚洲美女色播| 亚洲国产日韩一区二区| 青青草成人网| 精品人妻午夜一区二区三区四区 | 日韩久久久久久久| 国产精品熟女久久久久久| 99精品免费| 色狠狠av一区二区三区香蕉蜜桃| 亚洲成人av免费观看| 波多野结衣亚洲| 亚洲精品欧美专区| 日本精品一区| 欧美特级特黄aaaaaa在线看| 日本一不卡视频| 欧美激情xxxx性bbbb| 亚洲av成人无码久久精品 | 国产精品久久久久久久久久久久冷 | 波多野结衣高清视频| 一本一道久久a久久精品蜜桃| 日韩成人中文字幕| 两性午夜免费视频| 欧美成人性网| 亚洲福利电影网| 伊人久久青草| 久热av在线| 成人禁用看黄a在线| 成人亚洲欧美一区二区三区| 蜜臀精品一区二区三区| 日韩亚洲国产精品| 欧美国产精品日韩| 国产精品国产精品88| 精品黄色一级片| 日韩国产高清视频在线| 美女网站视频在线观看| 精品国产一区二区三区性色av| 色狠狠一区二区三区香蕉| 欧美一区二区激情| 亚洲电影视频在线| 亚洲天天做日日做天天谢日日欢| 日韩av电影免费在线观看| 亚洲 欧美 自拍偷拍| 成人动漫中文字幕| 99re视频| 国产三级视频在线播放| 久久国产精品第一页| 国产精品久久久久久久app| 日韩欧美成人一区二区三区| 在线亚洲成人| 国内精品400部情侣激情| 成年人av电影| 午夜精品999| 久久久精品影院| 免费高清在线观看电视| 日韩成人三级| 丝袜亚洲欧美日韩综合| 国产性猛交xx乱| 日韩成人精品一区二区| 日韩一区二区三区xxxx| 三级黄色录像视频| 亚洲精品tv久久久久久久久久| 伊人青青综合网站| 欧美肥妇bbwbbw| 希岛爱理一区二区三区| 蜜臀久久99精品久久久久久宅男 | 杨幂一区二区三区免费看视频| 亚洲成在人线av| av黄色一级片| 亚洲人成精品久久久 | 大伊人狠狠躁夜夜躁av一区| 1024av视频| 欧洲亚洲两性| 精品婷婷伊人一区三区三| 国内国产精品天干天干| 99久久999| 精品国产精品网麻豆系列 | 中国精品一区二区| 久久国产人妖系列| 高清视频在线观看一区| 四虎在线观看| 国产精品久久夜| 大荫蒂性生交片| gay欧美网站| 欧美日韩在线亚洲一区蜜芽| 26uuu国产| 牲欧美videos精品| 中文字幕日韩综合av| 欧美又粗又大又长| 久久激情久久| 91网在线免费观看| 五月婷婷六月色| 中文字幕精品在线不卡| 玖玖精品在线视频| 亚洲午夜天堂| 欧美一卡在线观看| 丰满少妇一区二区| 欧美在线资源| 国产97免费视| 国产女主播福利| 久久综合给合久久狠狠狠97色69| 国产精品亚洲天堂| 免费一二一二在线视频| 制服丝袜亚洲网站| 无码熟妇人妻av| 欧美涩涩视频| 国产欧美日韩精品丝袜高跟鞋| 开心激情综合网| 国产精品天天摸av网| aa视频在线播放| 亚洲狼人在线| 亚洲天堂一区二区三区| 精品深夜av无码一区二区老年| 全国精品久久少妇| 久久精品国产一区二区三区日韩| 成人在线免费看黄| 91官网在线观看| 日本精品一二三| 先锋资源久久| 国产精品嫩草影院久久久| 亚洲区小说区图片区| 亚洲精品ww久久久久久p站| 最新中文字幕免费视频| 香蕉一区二区| 国模精品视频一区二区| 精品黑人一区二区三区在线观看| 国产精品视频第一区| 日本精品一区在线观看| 久久久久高潮毛片免费全部播放| 久久精品在线视频| 亚洲天堂中文在线| 国产肉丝袜一区二区| 少妇性饥渴无码a区免费| 99ri日韩精品视频| 欧美另类高清videos| 97视频免费在线| 国产精品久久久一本精品| 久草综合在线观看| 精品国产aⅴ| 热门国产精品亚洲第一区在线| 亚洲成熟女性毛茸茸| 亚洲欧美日韩国产手机在线| 亚洲免费999| 久久高清免费| 国产精品一区久久| av在线三区| 欧美丝袜丝交足nylons| 成人在线手机视频| 蜜臀久久99精品久久久久宅男| 欧美精品成人一区二区在线观看| 午夜不卡影院| 亚洲人成电影网站色www| 久久久久久久久黄色| 久久久不卡网国产精品一区| 日韩毛片在线免费看| 久久99高清| 国产精品成人品| 大片免费播放在线视频| 欧美另类videos死尸| 欧美在线视频第一页| 国产精品亚洲综合一区在线观看| 激情六月天婷婷| 中文字幕一区二区三区中文字幕 | 色在线免费观看| 精品偷拍各种wc美女嘘嘘| 天堂网中文字幕| 中文字幕av在线一区二区三区| 波多结衣在线观看| 天天操夜夜操国产精品| caoporn国产精品免费公开| 538在线视频| 亚洲男人天堂2019| 在线观看免费观看在线| 亚洲美女屁股眼交| 中文字幕在线播放一区| 老牛嫩草一区二区三区日本| 亚洲三区视频| 日韩精品久久久久久久软件91| 久久久免费观看| 国产在线高清| 欧美高清www午色夜在线视频| 国产真实乱偷精品视频| 久久精品一区二区| 三级av免费看| 国产亚洲精品久久久久婷婷瑜伽| 神马影院我不卡午夜| 精品一区二区三区在线观看视频| 97国产真实伦对白精彩视频8| a黄色在线观看| 欧美成人精品福利| 日本熟女毛茸茸| 亚洲精品亚洲人成人网在线播放| 一级特黄a大片免费| 麻豆91在线播放| 精品少妇人欧美激情在线观看| 欧洲杯半决赛直播| 99在线热播| 影视一区二区三区| 欧美激情视频一区| 亚洲精品传媒| 国产视频综合在线| 成人黄色免费视频| 欧美性一二三区| 国产一级淫片a| 国产精品国产三级国产三级人妇| 欧美熟妇精品一区二区| 蜜桃av噜噜一区| 免费看日本毛片| 一区二区在线影院| 日韩经典在线视频| 国产精品17p| 91亚洲精品一区| 欧洲成人一区| 欧美在线性爱视频| 国产理论电影在线| 久久天天躁狠狠躁夜夜爽蜜月| 欧美精品少妇| 亚洲成人xxx| 国产女主播福利| 欧美日韩免费在线视频| 懂色av蜜臀av粉嫩av分享吧最新章节| 夜夜操天天操亚洲| 三级av在线免费观看| 99精品欧美一区二区三区综合在线| 欧美wwwwwww| 日韩精品电影一区亚洲| 欧美a v在线播放| 一区二区视频欧美| 黄色激情在线视频| 欧美精选一区| 黄色污污在线观看| 天天射综合网视频| 亚洲一区二区三区涩| 国产欧美日韩精品一区二区免费| 精品国产乱码久久久久久108| 日韩中文字幕无砖| 91久久久久久久一区二区| 99蜜月精品久久91| 国产激情视频一区| free欧美| 国产精彩精品视频| 四虎4545www精品视频| 日本高清久久天堂| 韩国成人动漫| 国产成人精品电影| 女生影院久久| 日本久久亚洲电影| 欧美电影网站| 国产福利视频一区| 成人av色网站| 国产欧美日韩视频| 91精品福利观看| 成人黄色av播放免费| 伊人久久精品| 97超级碰碰| 伊人久久影院| 国产丝袜不卡| 香蕉久久精品日日躁夜夜躁| 日本一区二区久久精品| 大色综合视频网站在线播放| 日韩中文字幕一区| 欧美3p视频| 黄色一级视频播放| 合欧美一区二区三区| 国内精品在线观看视频| 校园激情久久| 国产九九在线观看| 韩国视频一区二区| 国产亚洲色婷婷久久| eeuss国产一区二区三区| 野花社区视频在线观看| 欧美经典三级视频一区二区三区| 日本黄色录像视频| 亚洲一区二区免费视频| 久久精品国产成人av| 欧美色爱综合网| 国内精品国产成人国产三级| 亚洲电影免费观看高清完整版在线观看| 天堂网av2014| 中文字幕亚洲激情| 欧美一卡二卡| 国产成人免费av电影| 韩国一区二区三区视频| 激情小说综合区| 日本一区二区免费高清| 性高湖久久久久久久久aaaaa| 视频一区在线播放| 日本一二三四区视频| 久久美女艺术照精彩视频福利播放| 亚洲激情图片网| 亚洲一区二区欧美| 中文字幕免费观看视频| 亚洲成年人在线播放| yes4444视频在线观看| 欧美国产日韩一区二区在线观看| 香蕉成人av| av在线不卡一区| 色天天综合网| 91视频最新入口| 国产精品一二三四五| 亚洲精品国产熟女久久久| 亚洲尤物在线视频观看| 国产成人av免费| 亚洲精品wwww| 尤物yw193can在线观看| 日本视频久久久| 高潮久久久久久久久久久久久久 | 色偷偷中文字幕| 久久久久国产成人精品亚洲午夜 | 婷婷国产v国产偷v亚洲高清| 中文字幕精品在线观看| 精品丝袜一区二区三区| 欧美理论电影| 国产精品一区二区久久久久| 亚洲涩涩av| 男人添女荫道口女人有什么感觉| 青娱乐精品视频| 中文字幕av网址| 亚洲成a人v欧美综合天堂下载| 97人妻精品一区二区三区软件| 国产亚洲精品久久久久动| 岛国在线视频网站| www 成人av com| 99久久www免费| 五月激情婷婷在线| 国产午夜精品久久久久久久 | 无码一区二区精品| 一区二区三区欧美视频| 国产又粗又黄又爽| 中文字幕免费国产精品| 婷婷综合六月| 欧美精品久久久| 国产精品久久久久久久久久妞妞| 无码人妻一区二区三区免费n鬼沢| 最新日韩在线视频| 一本到在线视频| 自拍偷拍亚洲区| av在线不卡精品| 亚洲人成人77777线观看| 日韩精品色哟哟| 欧美三级视频网站| 在线精品国精品国产尤物884a| 飘雪影视在线观看免费观看| 欧洲中文字幕国产精品| 性欧美lx╳lx╳| 日韩a在线播放| 91视频.com| 欧美精品韩国精品| 亚洲人成电影网站色xx| 日本成人片在线| 亚洲电影一二三区| 九九九久久久精品| 91精品一区二区三区蜜桃| 337p亚洲精品色噜噜| 怡红院在线播放| 成人动漫在线视频| 激情综合亚洲| 中文精品在线观看| 日本韩国欧美在线| 在线看的av网站| 亚洲在线www| 亚洲久色影视| av网在线播放| 欧美精品日韩精品| 调教一区二区| 精品国产一区二区三区麻豆免费观看完整版 | 亚洲综合久久av一区二区三区| 欧美一区二区精品在线| 中文字幕在线观看网站| 国产精品一区二区三区不卡| 亚洲欧美清纯在线制服| 91精品国自产在线| 91麻豆精品91久久久久久清纯| 欧美理论片在线播放| 免费成人深夜夜行视频| 久久精品国产一区二区三区免费看| 国产人妻精品一区二区三区不卡| 日韩精品一区二区三区中文不卡| www在线观看黄色| 色之综合天天综合色天天棕色| 九九热在线视频观看这里只有精品 | 亚洲免费成人av在线| 污色网站在线观看| 一级女性全黄久久生活片免费| 日本成人一区| 91视频国产一区| 香蕉久久a毛片| 欧美黄色aaa| 国产视频在线一区二区| 99综合久久| 99色精品视频| 亚洲黄色片在线观看| 国产一区二区三区不卡在线| 69174成人网| 日韩精品91亚洲二区在线观看 |