System.Console.WriteLine() vs printfn в F #

В чем разница между следующими двумя утверждениями в F #? Являются ли они преимуществами или недостатками по сравнению друг с другом (исключая очевидные различия в синтаксисе)?

Я понимаю, что WriteLine() является частью .NET, но не понимаю, какие последствия это может иметь.

Пример кода:

printfn "This is an integer: %d" 5
System.Console.WriteLine("This is an integer: {0}" , 5)

Ответы

Ответ 1

printfn и его различные кузены имеют несколько преимуществ:

  • Они короче.
  • Они могут выполнять проверку <статического типа ; т.е. printfn "%d" "bad type" не будет компилироваться.
  • ... но вам не нужно проверять статический тип; %O печатает любой объект
  • Они могут печатать "умные" представления для таких вещей, как массивы, кортежи и дискриминационные объединения с помощью %A
  • Они могут быть частично применены; т.е. printfn "%d, %d" 3 является допустимым выражением. Это особенно примечательно, поскольку компилятор может проверить, что вы фактически применяете правильное количество аргументов, когда вы позже используете это подвыражение - в отличие от Console.WriteLine, которое с радостью примет слишком много или слишком мало параметров.

На практике наиболее распространенное частичное приложение, скорее всего, будет включать только строку формата; например.

let printParticle = printfn "Particle at (%d, %d), state %A, p = %f"

printParticle 2 3 //compile time warning about ignored value
printParticle 3 4 someState 0.4 //fine
printParticle 5 6 someState 0.4 0.7 //compile-time error

Однако, до F # 3.1, он также медленный. Это достаточно быстро, чтобы не отставать от вас кодер, но если вы используете его в какой-то форме сериализации, это может стать узким местом. Объявление F # 3.1 (которое распространяется как часть Visual Studio 2013) утверждает, что оно значительно улучшает производительность, хотя я еще не подтвердил это.

Лично я обычно использую printfn для поискового кодирования, а затем я в основном придерживаюсь %A со случайным другим спецификатором, который был добавлен. Однако собственное строковое форматирование .NET по-прежнему полезно в некоторых случаях для его детальной культуры и форматирования связанные варианты. Если вы хотите, чтобы прямая конкатенация максимальной скорости (или StringBuilder) легко превзошла обоих, поскольку это позволяет избежать интерпретации строки формата.

Ответ 2

Вот некоторые плюсы и минусы printf -подобных функций по сравнению с Console.WriteLine.

Плюсы:

  • printfn функции безопасны по типу:

    printfn "This is an integer: %i" 5 // works
    printfn "This is an integer: %i" "5" // doesn't compile
    
  • Легко выполнять частичное приложение с помощью printfn, что не относится к Console.WriteLine из-за чрезмерного количества перегрузок:

    [1; 2; 3] |> List.iter (printfn "%i; ")
    
  • printfn лучше поддерживать типы F # с помощью спецификатора %A.

Минусы:

Помимо невозможности повторного использования параметров в качестве упомянутого @mydogisbox, printfn-подобные функции намного медленнее, чем Console.WriteLine (из-за использования отражения); вы не должны использовать первую для целей ведения журнала.

Ответ 3

Функция printfn может быть частично применена.

let printDouble = printfn "%f"
printDouble 2.0

Поскольку стандартные функции .NET принимают кортежи как параметры в F #, вы не можете использовать там частичное приложение.

Второе преимущество printfn состоит в том, что аргументы вводятся. Так что это не скомпилируется:

let printDouble = printfn "%d"
printDouble 2.0

Ответ 4

Помимо стиля, System.Console.WriteLine имеет то преимущество, что он может повторно использовать параметры, т.е. System.Console.WriteLine("This is a integer twice: {0} {0}", 5)

Кроме того, как отмечено здесь, вы можете сделать довольно печатную работу над объектом F #, используя printfn, который вы не можете сделать с System.Console.WriteLine, и поскольку он не работает, t возьмите кортеж, вы можете сделать с ним частичное приложение.

Как отмечалось другими, printfn использует отражение и, следовательно, значительно медленнее, чем PrintLine, но также является типичным.