如何在 elm-core > 5.0.0 中将 Json.Decoder 中的 String 转换为 Int
How to convert from String to Int in Json.Decoder in elm-core > 5.0.0
这与 相同,只是 elm 从那时起发生了变化,因此答案不再有效(特别是不再有 Decode.customDecoder
对象)。
如何在 elm-core > 5.0.0 中做同样的事情?
一种方法(从 Elm 0.18 和核心 5.0 开始)是这样的:
stringIntDecoder : Decoder Int
stringIntDecoder =
Json.Decode.map (\str -> String.toInt (str) |> Result.withDefault 0) Json.Decode.string
标准库中的 String.toInt
函数接受一个字符串并尝试将其转换为整数,并返回一个结果。 Result.withDefault
就像它的名字所暗示的那样——你给它一些默认值和一个结果,如果结果是 Ok x
你得到 x
但如果它是 Err _
你得到您提供的默认值,此处为 0。如果愿意,您可以自己编写一个函数来处理结果,然后传递该函数。
鉴于在对其他答案的评论中,您声明需要接受可能的失败,您可以使用 Maybe。
stringIntDecoder : Decoder (Maybe Int)
stringIntDecoder =
Json.Decode.map (String.toInt >> Result.toMaybe) Json.Decode.string
或者
stringIntDecoder : Decoder (Result String Int)
stringIntDecoder =
Json.Decode.map (String.toInt) Json.Decode.string
您可以使用 Json.Decode
中的 succeed
和 fail
创建自己的自定义解码器。我更改了下面的参数顺序以使其可链接。
编辑:将解码器问题与结果问题分开。
import Json.Decode as Json
import Result
-- // This is a Result helper function that could be used elsewhere.
-- // Currently, there is no Result.either in Elm core.
eitherR : (x -> b) -> (a -> b) -> Result x a -> b
eitherR fErr fOk result =
case result of
Err x ->
fErr x
Ok a ->
fOk a
customDecoder : (a -> Result String b) -> Json.Decoder a -> Json.Decoder b
customDecoder fResult decoder =
decoder |> Json.andThen (fResult >> eitherR Json.fail Json.succeed)
将其插入链接的问题...
let number =
Json.oneOf [ Json.int, Json.string |> customDecoder String.toInt ]
这是另一个使用示例。这是 onChange
的一个版本,它将值转换为整数。当您知道选项值是 Int 时,主要对 select
有用。
import Html
import Html.Attributes exposing (..)
import Html.Events exposing (..)
import String
onChangeInt : (Int -> msg) -> Attribute msg
onChangeInt fMsg =
on "change" (targetValue |> customDecoder String.toInt |> Json.map fMsg)
注意targetValue
定义在Html.Events模块中:
targetValue : Decoder String
decodeString parseInt """ "123" """
查看 tutorial about custom decoders, like for date. Reuse fromResult
方法。
阅读 function composition (<<),它在 parseInt
函数中使用。
对于使用 targetValue 文档的 Elm 0.19,代码变为:
import Html.Events
import Json.Decode
onIntInput : (Int -> msg) -> Attribute msg
onIntInput tagger =
Html.Events.stopPropagationOn "input" <|
Json.Decode.map alwaysStop (Json.Decode.map tagger targetIntValue)
targetIntValue : Decoder Int
targetIntValue =
Json.Decode.at ["target", "value"] Json.Decode.string |> Json.Decode.andThen (\value ->
case String.toInt value of
Just number -> Json.Decode.succeed number
Nothing -> Json.Decode.fail "not a number")
alwaysStop : a -> (a, Bool)
alwaysStop x =
(x, True)
然后您可以在使用 onInput 的地方使用 onIntInput。
这是一个避免必须选择粗略默认值的解决方案:
import Json.Decode as Decode exposing (Decoder)
decodeIntString : Decoder (Maybe Int)
decodeIntString =
Decode.map String.toInt Decode.string
decodeMaybeFail : Maybe a -> Decoder a
decodeMaybeFail val =
case val of
Just a ->
Decode.succeed a
Nothing ->
Decode.fail "'Nothing' value can't be decoded"
然后您将它与
一起使用
Decode.andThen decodeMaybeFail decodeIntString
(这是 Decoder Int
类型,因此您可以像使用 Decode.int
一样使用它)
起初并不明显,但它说明了如何将这个问题分解成简单的小步骤。
我认为函数 decodeMaybeFail : Maybe a -> Decoder a
应该在标准 Json.Decode
模块中。
这与 Decode.customDecoder
对象)。
如何在 elm-core > 5.0.0 中做同样的事情?
一种方法(从 Elm 0.18 和核心 5.0 开始)是这样的:
stringIntDecoder : Decoder Int
stringIntDecoder =
Json.Decode.map (\str -> String.toInt (str) |> Result.withDefault 0) Json.Decode.string
标准库中的 String.toInt
函数接受一个字符串并尝试将其转换为整数,并返回一个结果。 Result.withDefault
就像它的名字所暗示的那样——你给它一些默认值和一个结果,如果结果是 Ok x
你得到 x
但如果它是 Err _
你得到您提供的默认值,此处为 0。如果愿意,您可以自己编写一个函数来处理结果,然后传递该函数。
鉴于在对其他答案的评论中,您声明需要接受可能的失败,您可以使用 Maybe。
stringIntDecoder : Decoder (Maybe Int)
stringIntDecoder =
Json.Decode.map (String.toInt >> Result.toMaybe) Json.Decode.string
或者
stringIntDecoder : Decoder (Result String Int)
stringIntDecoder =
Json.Decode.map (String.toInt) Json.Decode.string
您可以使用 Json.Decode
中的 succeed
和 fail
创建自己的自定义解码器。我更改了下面的参数顺序以使其可链接。
编辑:将解码器问题与结果问题分开。
import Json.Decode as Json
import Result
-- // This is a Result helper function that could be used elsewhere.
-- // Currently, there is no Result.either in Elm core.
eitherR : (x -> b) -> (a -> b) -> Result x a -> b
eitherR fErr fOk result =
case result of
Err x ->
fErr x
Ok a ->
fOk a
customDecoder : (a -> Result String b) -> Json.Decoder a -> Json.Decoder b
customDecoder fResult decoder =
decoder |> Json.andThen (fResult >> eitherR Json.fail Json.succeed)
将其插入链接的问题...
let number =
Json.oneOf [ Json.int, Json.string |> customDecoder String.toInt ]
这是另一个使用示例。这是 onChange
的一个版本,它将值转换为整数。当您知道选项值是 Int 时,主要对 select
有用。
import Html
import Html.Attributes exposing (..)
import Html.Events exposing (..)
import String
onChangeInt : (Int -> msg) -> Attribute msg
onChangeInt fMsg =
on "change" (targetValue |> customDecoder String.toInt |> Json.map fMsg)
注意targetValue
定义在Html.Events模块中:
targetValue : Decoder String
decodeString parseInt """ "123" """
查看 tutorial about custom decoders, like for date. Reuse fromResult
方法。
阅读 function composition (<<),它在 parseInt
函数中使用。
对于使用 targetValue 文档的 Elm 0.19,代码变为:
import Html.Events
import Json.Decode
onIntInput : (Int -> msg) -> Attribute msg
onIntInput tagger =
Html.Events.stopPropagationOn "input" <|
Json.Decode.map alwaysStop (Json.Decode.map tagger targetIntValue)
targetIntValue : Decoder Int
targetIntValue =
Json.Decode.at ["target", "value"] Json.Decode.string |> Json.Decode.andThen (\value ->
case String.toInt value of
Just number -> Json.Decode.succeed number
Nothing -> Json.Decode.fail "not a number")
alwaysStop : a -> (a, Bool)
alwaysStop x =
(x, True)
然后您可以在使用 onInput 的地方使用 onIntInput。
这是一个避免必须选择粗略默认值的解决方案:
import Json.Decode as Decode exposing (Decoder)
decodeIntString : Decoder (Maybe Int)
decodeIntString =
Decode.map String.toInt Decode.string
decodeMaybeFail : Maybe a -> Decoder a
decodeMaybeFail val =
case val of
Just a ->
Decode.succeed a
Nothing ->
Decode.fail "'Nothing' value can't be decoded"
然后您将它与
一起使用Decode.andThen decodeMaybeFail decodeIntString
(这是 Decoder Int
类型,因此您可以像使用 Decode.int
一样使用它)
起初并不明显,但它说明了如何将这个问题分解成简单的小步骤。
我认为函数 decodeMaybeFail : Maybe a -> Decoder a
应该在标准 Json.Decode
模块中。