记得Facebook曾经在一次社区活动上说过,随着他们越来越多地使用Javascript,很快就面临了曾经在PHP上遇到的问题:这东西到底是啥?
动态语言就像把双刃剑,你可以爱死它的灵活性,也可能因为一个小的疏忽而损失惨重。Elm选择了静态强类型,这通常也是多数函数式语言的选择,没有了OO语言中 类的概念,强大的类型系统负责解决一切“这是什么?”的问题
类型注解
也可以叫做类型签名,Elm 使用冒号 :来注明类型,在Hello world的基础上,让我们分别定义一个变量和函数,并且注明类型
import Html exposing (..)import Html.Attributes exposing (..)elm : Stringelm = "elm"sayHello : String -> StringsayHello name = "Hello, " ++ namemain = div [class "hello"] [ span [] [text (sayHello elm)] ]
尝试将elm的值”elm”改为数字,看看会发生什么?
Detected errors in 1 module.-- TYPE MISMATCH ---------------------------------------------------------------The type annotation for `elm` does not match its definition.5| elm : String ^^^^^^The type annotation is saying: StringBut I am inferring that the definition has this type: number
编译器发现了错误,并且能够定位到具体的行数。
如果不声明类型呢?如果注释掉类型注解
import Html exposing (..)import Html.Attributes exposing (..)--elm : Stringelm = 6--sayHello : String -> StringsayHello name = "Hello, " ++ namemain = div [class "hello"] [ span [] [text (sayHello elm)] ]
重新编译,还是会报错,只是错误信息变了,这次是第14行:
Detected errors in 1 module.-- TYPE MISMATCH ---------------------------------------------------------------The argument to function `sayHello` is causing a mismatch.14| sayHello elm) ^^^Function `sayHello` is expecting the argument to be: StringBut it is: number
即使没有显式的类型注解,Elm的类型推导系统也会发挥作用,此处通过类型推导认为 sayHello函数的参数应该是字符串,但是传入了数字,因此报错。
对比两次不同的错误提示可以看出,类型注解能让编译器更准确地发现和定位错误。随着学习的深入你会慢慢喜欢上类型系统带来的安全感:如果编译失败,明确的提示能帮助你快速定位问题。而只要编译通过,程序就一定能运行。
基本类型和List
基本类型
基本类型和多数语言是类似的,无非就是 String, Char, Bool Int, Float,可以参考官网的 literals。需要注意在Elm中, String必须用双引号,单引号是用来表示 Char的,字符串单引号党需要适应一下。
List
严格来说List并不是类型,它的类型是 List a,其中的 a被称作 类型变量,这是因为List作为容器,它可以装String,Int,或者什么都不装,因此类型必须是动态的:
> [ "Alice", "Bob" ][ "Alice", "Bob" ] : List String> [ 1.0, 8.6, 42.1 ][ 1.0, 8.6, 42.1 ] : List Float> [][] : List a
关于 类型变量后面会继续讨论,在这里我们只需要记住一点: List不是类型,类似List String这样的才是。
由于参数只有一个,Elm的List只能容纳单一类型的元素,和Javascript来者不拒的List不同,下面这样的是会被编译器发现并报错的:
list = [1, "a"]
类型别名
类型别名用于组合或复用已知的类型,比如
type alias Name = Stringtype alias Age = Int type alias User = {name: Name, age: Age}user : Useruser = { name = "Zhang zhe", age = 89 } setUserName : String -> User -> UsersetUserName name user = {user | name = name}
它不仅可以让基本类型具备业务语义,还可以为复杂的数据结构组合出合适的、语义化的类型。没有别名的话,setUserName的类型签名就得写成下面这样……一坨:
setUserName : String -> {name: String, age: Int} -> {name: String, age: Int}
Union Types
Union type 是Elm类型系统中最重要的部分之一,它用来表示一组可能的值,每个值叫做一个 Tag,如下:
type Bool = True | Falsetype User = Anonymos | Authed
其中 True和 False, Anonymos和 Authed都是 Tag名( 注意Tag不是Type)。看起来很像枚举?不只这样,Union type强大的地方在于: Tag可以携带一组已知类型。上面的代码我们虽然能区分两类用户,但并不能获取认证用户的名称,这时候就可以用已知类型结合Tag表达:
type User = Anonymos | Authed String
当我们创建Union type的时候,实际上为每个 Tag都创建了相应的 值构造器:
> type User = Anonymous | Authed String> AnonymousAnonymous : User> AuthedAuthed : String -> User
不带其它信息的Anonymous可以直接作为 值使用(想想 True和 False),而带有已知类型的Authed实际上是一个函数,它接受String,返回User类型:
users : List Userusers = [ Anonymous, Authed "Kpax"]
在Haskell中没有Tag的叫法,相似的东西就叫 值构造器(value constructor),直接的表明了它的用途:构建属于该类型的值
Tag还可以被解构:
getAuthedUserName : User -> StringgetAuthedUserName user = case user of Anonymous -> "" Authed name -> name
这个函数返回Authed用户的名称,如果是Anonymous用户则返回空字符串。
完整的可在在线编辑器中执行的代码如下:
import Html exposing (..)import Listtype User = Anonymous | Authed Stringusers : List Userusers = [ Anonymous, Authed "Kpax", Authed "qin"]getAuthedUserName : User -> StringgetAuthedUserName user = case user of Anonymous -> "" Authed name -> name main = div [] (List.map (text << getAuthedUserName) users)
text
Type variables
上面已经提到了 List a类型,其中 a即类型变量,表示一个当前还不确定的类型,类似于面向对象编程中泛型的概念
map函数的类型签名也使用了类型变量:
map : (a -> b) -> a -> b
这使得我们调用map函数 map userToString user时,只要保证user是User类型即可,map函数并不关心具体的类型。
那么如何定义一个 List a类型呢?代码如下
type List a = Empty | Node a (List a)
前面说到 Tag可以携带已知类型,那么是否可以携带正在定义的这个类型呢?答案是肯定的!这就是类型的 递归, List a就是这样一个带有类型参数的递归类型,平时我们写的数组,可以理解为如下代码的语法糖
-- []Empty-- [1]Node 1 Empty-- [1, 2, 3]Node 1 (Node 2 (Node 3 Empty))
同样的思路,我们完全可以自己实现二叉树等数据结构,有兴趣的朋友不妨试试,官方文档有 相关章节可供参考
Counter with type
上一章[基础篇]()我们讲了Counter的实现,代码如下:
import Html exposing (..)import Html.Events exposing (onClick)import Html.App as Apptype Msg = Increment | Decrementupdate msg model = case msg of Increment -> model + 1 Decrement -> model - 1view model = div [] [ button [onClick Decrement] [text "-"] , text (toString model) , button [onClick Increment] [text "+"] ]initModel = 3main = App.beginnerProgram {model = initModel, view = view, update = update}
让我们用刚刚学习的知识给以上代码添加类型和类型注解
首先,我们有 initModel这个数据,它的类型是 Int,不具备任何业务语义,让我们定义一个类型别名 Model来表示Counter的数据
type alias Model = Int
自然 initModel的类型应该为 Model
initModel : ModelinitModel = 3
update函数的类型签名比较简单,它接受消息 Msg和当前数据 Model,返回新的数据 Model:
update : Msg -> Model -> Model
view函数接受 Model类型的数据,返回什么呢?如果查阅 div函数的 文档,你会发现返回的是一个带有类型变量的类型 Html msg。其实很好理解,因为渲染界面的函数不仅要输出Html,当事件发生时还要输出 消息,输出消息的类型,就是应该赋给变量 msg的类型,在 Counter中消息的类型是 Msg,因此:
view : Model -> Html Msg
完整代码:
import Html exposing (..)import Html.Events exposing (onClick)import Html.App as Apptype alias Model = Inttype Msg = Increment | Decrementupdate : Msg -> Model -> Modelupdate msg model = case msg of Increment -> model + 1 Decrement -> model - 1view : Model -> Html Msgview model = div [] [ button [onClick Decrement] [text "-"] , text (toString model) , button [onClick Increment] [text "+"] ]initModel : ModelinitModel = 3main = App.beginnerProgram {model = initModel, view = view, update = update}
总结
类型的学习可能有些枯燥,但是非常重要。如果你了解redux,你会发现Union type简直天生就是做action的料,比起redux在javascript中使用的字符串既简洁又达意,甚至还可以嵌套组合,谈笑风生!高到不知道哪里去了!
下一章我们将把在线编辑器放到一边,把Counter迁移到本地运行,然后实现一个CounterList,在CounterList中,你会看到Elm是如何复用组件,以及为什么Elm被称为理想的 分形架构。
各种架构对比,可以参考Cycle.js作者Andre Staltz的 文章 `elm

HTML의 미래 트렌드는 의미론 및 웹 구성 요소이며 CSS의 미래 트렌드는 CSS-In-JS 및 CSShoudini이며, JavaScript의 미래 트렌드는 WebAssembly 및 서버리스입니다. 1. HTML 시맨틱은 접근성과 SEO 효과를 향상시키고 웹 구성 요소는 개발 효율성을 향상 시키지만 브라우저 호환성에주의를 기울여야합니다. 2. CSS-in-JS는 스타일 관리 유연성을 향상 시키지만 파일 크기를 증가시킬 수 있습니다. CSShoudini는 CSS 렌더링의 직접 작동을 허용합니다. 3. Webosembly는 브라우저 애플리케이션 성능을 최적화하지만 가파른 학습 곡선을 가지고 있으며 서버리스는 개발을 단순화하지만 콜드 스타트 문제의 최적화가 필요합니다.

웹 개발에서 HTML, CSS 및 JavaScript의 역할은 다음과 같습니다. 1. HTML은 웹 페이지 구조를 정의하고, 2. CSS는 웹 페이지 스타일을 제어하고 3. JavaScript는 동적 동작을 추가합니다. 그들은 함께 현대 웹 사이트의 프레임 워크, 미학 및 상호 작용을 구축합니다.

HTML의 미래는 무한한 가능성으로 가득합니다. 1) 새로운 기능과 표준에는 더 많은 의미 론적 태그와 WebComponents의 인기가 포함됩니다. 2) 웹 디자인 트렌드는 반응적이고 접근 가능한 디자인을 향해 계속 발전 할 것입니다. 3) 성능 최적화는 반응 형 이미지 로딩 및 게으른로드 기술을 통해 사용자 경험을 향상시킬 것입니다.

웹 개발에서 HTML, CSS 및 JavaScript의 역할은 다음과 같습니다. HTML은 컨텐츠 구조를 담당하고 CSS는 스타일을 담당하며 JavaScript는 동적 동작을 담당합니다. 1. HTML은 태그를 통해 웹 페이지 구조와 컨텐츠를 정의하여 의미를 보장합니다. 2. CSS는 선택기와 속성을 통해 웹 페이지 스타일을 제어하여 아름답고 읽기 쉽게 만듭니다. 3. JavaScript는 스크립트를 통해 웹 페이지 동작을 제어하여 동적 및 대화식 기능을 달성합니다.

Htmlisnotaprogramminglanguage; itisamarkuplanguage.1) htmlstructuresandformatswebcontentusingtags.2) itworksporstylingandjavaScriptOfforIncincivity, WebDevelopment 향상.

HTML은 웹 페이지 구조를 구축하는 초석입니다. 1. HTML은 컨텐츠 구조와 의미론 및 사용 등을 정의합니다. 태그. 2. SEO 효과를 향상시키기 위해 시맨틱 마커 등을 제공합니다. 3. 태그를 통한 사용자 상호 작용을 실현하려면 형식 검증에주의를 기울이십시오. 4. 자바 스크립트와 결합하여 동적 효과를 달성하기 위해 고급 요소를 사용하십시오. 5. 일반적인 오류에는 탈수 된 레이블과 인용되지 않은 속성 값이 포함되며 검증 도구가 필요합니다. 6. 최적화 전략에는 HTTP 요청 감소, HTML 압축, 시맨틱 태그 사용 등이 포함됩니다.

HTML은 웹 페이지를 작성하는 데 사용되는 언어로, 태그 및 속성을 통해 웹 페이지 구조 및 컨텐츠를 정의합니다. 1) HTML과 같은 태그를 통해 문서 구조를 구성합니다. 2) 브라우저는 HTML을 구문 분석하여 DOM을 빌드하고 웹 페이지를 렌더링합니다. 3) 멀티미디어 기능을 향상시키는 HTML5의 새로운 기능. 4) 일반적인 오류에는 탈수 된 레이블과 인용되지 않은 속성 값이 포함됩니다. 5) 최적화 제안에는 시맨틱 태그 사용 및 파일 크기 감소가 포함됩니다.

WebDevelopmentReliesonHtml, CSS 및 JavaScript : 1) HtmlStructuresContent, 2) CSSSTYLESIT, 및 3) JAVASCRIPTADDSINGINTERACTIVITY, BASISOFMODERNWEBEXPERIENCES를 형성합니다.


핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

AI Hentai Generator
AI Hentai를 무료로 생성하십시오.

인기 기사

뜨거운 도구

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

MinGW - Windows용 미니멀리스트 GNU
이 프로젝트는 osdn.net/projects/mingw로 마이그레이션되는 중입니다. 계속해서 그곳에서 우리를 팔로우할 수 있습니다. MinGW: GCC(GNU Compiler Collection)의 기본 Windows 포트로, 기본 Windows 애플리케이션을 구축하기 위한 무료 배포 가능 가져오기 라이브러리 및 헤더 파일로 C99 기능을 지원하는 MSVC 런타임에 대한 확장이 포함되어 있습니다. 모든 MinGW 소프트웨어는 64비트 Windows 플랫폼에서 실행될 수 있습니다.

드림위버 CS6
시각적 웹 개발 도구

mPDF
mPDF는 UTF-8로 인코딩된 HTML에서 PDF 파일을 생성할 수 있는 PHP 라이브러리입니다. 원저자인 Ian Back은 자신의 웹 사이트에서 "즉시" PDF 파일을 출력하고 다양한 언어를 처리하기 위해 mPDF를 작성했습니다. HTML2FPDF와 같은 원본 스크립트보다 유니코드 글꼴을 사용할 때 속도가 느리고 더 큰 파일을 생성하지만 CSS 스타일 등을 지원하고 많은 개선 사항이 있습니다. RTL(아랍어, 히브리어), CJK(중국어, 일본어, 한국어)를 포함한 거의 모든 언어를 지원합니다. 중첩된 블록 수준 요소(예: P, DIV)를 지원합니다.

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경
